This is the html version of the file http://www.mhatt.aps.anl.gov/dohn/programming/gtk-2.0/gtk-tutorial.pdf.
G o o g l e automatically generates html versions of documents as we crawl the web.
To link to or bookmark this page, use the following url: http://www.google.com/search?q=cache:MV9EKv_uhqEJ:www.mhatt.aps.anl.gov/dohn/programming/gtk-2.0/gtk-tutorial.pdf+download+%22GTK%2B+2.0+Tutorial%22&hl=en


Google is not affiliated with the authors of this page nor responsible for its content.
These search terms have been highlighted:  download  gtk+  2.0  tutorial 

Page 1
GTK+ 2.0 Tutorial
Tony Gale
Ian Main
& the GTK team

Page 2
GTK+ 2.0 Tutorial
by Tony Gale, Ian Main, and & the GTK team
This is a tutorial on how to use GTK (the GIMP Toolkit) through its C interface.

Page 3
Table of Contents
1. Introduction............................................................................................................................................1
2. Getting Started.......................................................................................................................................3
2.1. Hello World in GTK....................................................................................................................4
2.2. Compiling Hello World...............................................................................................................6
2.3. Theory of Signals and Callbacks ................................................................................................7
2.4. Events..........................................................................................................................................9
2.5. Stepping Through Hello World.................................................................................................11
3. Moving On............................................................................................................................................15
3.1. Data Types.................................................................................................................................15
3.2. More on Signal Handlers ..........................................................................................................15
3.3. An Upgraded Hello World ........................................................................................................16
4. Packing Widgets...................................................................................................................................19
4.1. Theory of Packing Boxes..........................................................................................................19
4.2. Details of Boxes........................................................................................................................19
4.3. Packing Demonstration Program ..............................................................................................20
4.4. Packing Using Tables................................................................................................................26
4.5. Table Packing Example.............................................................................................................28
5. Widget Overview..................................................................................................................................32
5.1. Casting ......................................................................................................................................32
5.2. Widget Hierarchy......................................................................................................................33
5.3. Widgets Without Windows........................................................................................................35
6. The Button Widget ..............................................................................................................................36
6.1. Normal Buttons.........................................................................................................................36
6.2. Toggle Buttons ..........................................................................................................................38
6.3. Check Buttons...........................................................................................................................39
6.4. Radio Buttons............................................................................................................................40
7. Adjustments..........................................................................................................................................43
7.1. Creating an Adjustment ............................................................................................................43
7.2. Using Adjustments the Easy Way.............................................................................................44
7.3. Adjustment Internals.................................................................................................................44
8. Range Widgets .....................................................................................................................................47
8.1. Scrollbar Widgets......................................................................................................................47
8.2. Scale Widgets............................................................................................................................47
8.2.1. Creating a Scale Widget ...............................................................................................47
8.2.2. Functions and Signals (well, functions, at least)..........................................................48
8.3. Common Range Functions........................................................................................................49
8.3.1. Setting the Update Policy .............................................................................................49
8.3.2. Getting and Setting Adjustments..................................................................................50
8.4. Key and Mouse bindings...........................................................................................................50
8.5. Example ....................................................................................................................................51
iii

Page 4
9. Miscellaneous Widgets ........................................................................................................................57
9.1. Labels........................................................................................................................................57
9.2. Arrows.......................................................................................................................................60
9.3. The Tooltips Object...................................................................................................................62
9.4. Progress Bars.............................................................................................................................63
9.5. Dialogs ......................................................................................................................................69
9.6. Rulers ........................................................................................................................................70
9.7. Statusbars ..................................................................................................................................73
9.8. Text Entries ...............................................................................................................................76
9.9. Spin Buttons..............................................................................................................................79
9.10. Combo Box .............................................................................................................................86
9.11. Calendar ..................................................................................................................................89
9.12. Color Selection........................................................................................................................99
9.13. File Selections.......................................................................................................................103
10. Container Widgets...........................................................................................................................106
10.1. The EventBox........................................................................................................................106
10.2. The Alignment widget ..........................................................................................................107
10.3. Fixed Container.....................................................................................................................108
10.4. Layout Container...................................................................................................................110
10.5. Frames...................................................................................................................................111
10.6. Aspect Frames.......................................................................................................................113
10.7. Paned Window Widgets ........................................................................................................114
10.8. Viewports ..............................................................................................................................118
10.9. Scrolled Windows .................................................................................................................119
10.10. Button Boxes.......................................................................................................................121
10.11. Toolbar ................................................................................................................................124
10.12. Notebooks ...........................................................................................................................131
11. Menu Widget....................................................................................................................................138
11.1. Manual Menu Creation .........................................................................................................138
11.2. Manual Menu Example.........................................................................................................141
11.3. Using ItemFactory.................................................................................................................144
11.4. Item Factory Example...........................................................................................................144
12. Undocumented Widgets ..................................................................................................................147
12.1. Accel Label ...........................................................................................................................147
12.2. Option Menu .........................................................................................................................147
12.3. Menu Items ...........................................................................................................................147
12.3.1. Check Menu Item .....................................................................................................147
12.3.2. Radio Menu Item......................................................................................................147
12.3.3. Separator Menu Item................................................................................................147
12.3.4. Tearoff Menu Item....................................................................................................147
12.4. Curves ...................................................................................................................................147
12.5. Drawing Area........................................................................................................................148
12.6. Font Selection Dialog............................................................................................................148
12.7. Message Dialog.....................................................................................................................148
12.8. Gamma Curve .......................................................................................................................148
12.9. Image.....................................................................................................................................148
iv

Page 5
12.10. Plugs and Sockets................................................................................................................148
12.11. Tree View ............................................................................................................................148
12.12. Text View ............................................................................................................................148
13. Setting Widget Attributes ...............................................................................................................149
14. Timeouts, IO and Idle Functions....................................................................................................150
14.1. Timeouts................................................................................................................................150
14.2. Monitoring IO .......................................................................................................................150
14.3. Idle Functions........................................................................................................................151
15. Advanced Event and Signal Handling...........................................................................................152
15.1. Signal Functions....................................................................................................................152
15.1.1. Connecting and Disconnecting Signal Handlers......................................................152
15.1.2. Blocking and Unblocking Signal Handlers..............................................................152
15.1.3. Emitting and Stopping Signals.................................................................................152
15.2. Signal Emission and Propagation .........................................................................................153
16. Managing Selections........................................................................................................................155
16.1. Overview...............................................................................................................................155
16.2. Retrieving the selection.........................................................................................................155
16.3. Supplying the selection.........................................................................................................158
17. Drag-and-drop (DND).....................................................................................................................162
17.1. Overview...............................................................................................................................162
17.2. Properties ..............................................................................................................................162
17.3. Functions...............................................................................................................................163
17.3.1. Setting up the source widget.....................................................................................163
17.3.2. Signals on the source widget:...................................................................................164
17.3.3. Setting up a destination widget: ...............................................................................164
17.3.4. Signals on the destination widget:............................................................................165
18. GLib ..................................................................................................................................................166
18.1. Definitions.............................................................................................................................166
18.2. Doubly Linked Lists..............................................................................................................167
18.3. Singly Linked Lists ...............................................................................................................168
18.4. Memory Management...........................................................................................................169
18.5. Timers....................................................................................................................................170
18.6. String Handling.....................................................................................................................170
18.7. Utility and Error Functions ...................................................................................................171
19. GTK’s rc Files ..................................................................................................................................173
19.1. Functions For rc Files............................................................................................................173
19.2. GTK’s rc File Format............................................................................................................174
19.3. Example rc file ......................................................................................................................175
20. Writing Your Own Widgets ............................................................................................................179
20.1. Overview...............................................................................................................................179
20.2. The Anatomy Of A Widget...................................................................................................179
20.3. Creating a Composite widget................................................................................................180
20.3.1. Introduction ..............................................................................................................180
20.3.2. Choosing a parent class ............................................................................................180
20.3.3. The header file..........................................................................................................180
v

Page 6
20.3.4. The
_get_type()
function.....................................................................................182
20.3.5. The
_class_init()
function ................................................................................183
20.3.6. The
_init()
function .............................................................................................185
20.3.7. And the rest...............................................................................................................186
20.4. Creating a widget from scratch .............................................................................................188
20.4.1. Introduction ..............................................................................................................189
20.4.2. Displaying a widget on the screen............................................................................189
20.4.3. The origins of the Dial Widget.................................................................................189
20.4.4. The Basics ................................................................................................................190
20.4.5.
gtk_dial_realize()
...........................................................................................195
20.4.6. Size negotiation ........................................................................................................196
20.4.7.
gtk_dial_expose()
.............................................................................................197
20.4.8. Event handling..........................................................................................................198
20.4.9. Possible Enhancements ............................................................................................204
20.5. Learning More.......................................................................................................................204
21. Scribble, A Simple Example Drawing Program ...........................................................................205
21.1. Overview...............................................................................................................................205
21.2. Event Handling......................................................................................................................205
21.3. The DrawingArea Widget, And Drawing .............................................................................208
21.4. Adding XInput support .........................................................................................................212
21.4.1. Enabling extended device information.....................................................................213
21.4.2. Using extended device information..........................................................................214
21.4.3. Finding out more about a device ..............................................................................216
21.4.4. Further sophistications..............................................................................................217
22. Tips For Writing GTK Applications..............................................................................................219
23. Contributing.....................................................................................................................................220
24. Credits...............................................................................................................................................221
25. Tutorial Copyright and Permissions Notice ..................................................................................222
A. GTK Signals ......................................................................................................................................223
A.1. GtkObject ...............................................................................................................................223
A.2. GtkWidget ..............................................................................................................................223
A.3. GtkData ..................................................................................................................................226
A.4. GtkContainer..........................................................................................................................226
A.5. GtkCalendar ...........................................................................................................................227
A.6. GtkEditable ............................................................................................................................227
A.7. GtkNotebook..........................................................................................................................228
A.8. GtkList....................................................................................................................................228
A.9. GtkMenuShell ........................................................................................................................228
A.10. GtkToolbar ...........................................................................................................................229
A.11. GtkButton.............................................................................................................................229
A.12. GtkItem ................................................................................................................................229
A.13. GtkWindow ..........................................................................................................................229
A.14. GtkHandleBox......................................................................................................................230
A.15. GtkToggleButton..................................................................................................................230
A.16. GtkMenuItem .......................................................................................................................230
A.17. GtkCheckMenuItem.............................................................................................................230
vi

Page 7
A.18. GtkInputDialog ....................................................................................................................230
A.19. GtkColorSelection................................................................................................................230
A.20. GtkStatusBar ........................................................................................................................230
A.21. GtkCurve..............................................................................................................................231
A.22. GtkAdjustment .....................................................................................................................231
B. GDK Event Types..............................................................................................................................232
C. Code Examples..................................................................................................................................240
C.1. Tictactoe .................................................................................................................................240
C.1.1. tictactoe.h...................................................................................................................240
C.1.2. tictactoe.c...................................................................................................................241
C.1.3. ttt_test.c......................................................................................................................244
C.2. GtkDial ...................................................................................................................................245
C.2.1. gtkdial.h .....................................................................................................................245
C.2.2. gtkdial.c......................................................................................................................247
C.2.3. dial_test.c...................................................................................................................259
C.3. Scribble...................................................................................................................................261
C.3.1. scribble-simple.c........................................................................................................261
C.3.2. scribble-xinput.c ........................................................................................................264
vii

Page 8
List of Tables
17-1. Source widget signals.....................................................................................................................164
17-2. Destination widget signals..............................................................................................................165
viii

Page 9
Chapter 1. Introduction
GTK (GIMP Toolkit) is a library for creating graphical user interfaces. It is licensed using the LGPL
license, so you can develop open software, free software, or even commercial non-free software using
GTK without having to spend anything for licenses or royalties.
It’s called the GIMP toolkit because it was originally written for developing the GNU Image
Manipulation Program (GIMP), but GTK has now been used in a large number of software projects,
including the GNU Network Object Model Environment (GNOME) project. GTK is built on top of GDK
(GIMP Drawing Kit) which is basically a wrapper around the low-level functions for accessing the
underlying windowing functions (Xlib in the case of the X windows system), and gdk-pixbuf, a library
for client-side image manipulation.
The primary authors of GTK are:
Peter Mattis petm@xcf.berkeley.edu (mailto:petm@xcf.berkeley.edu)
Spencer Kimball spencer@xcf.berkeley.edu (mailto:spencer@xcf.berkeley.edu)
Josh MacDonald jmacd@xcf.berkeley.edu (mailto:jmacd@xcf.berkeley.edu)
GTK is currently maintained by:
Owen Taylor otaylor@redhat.com (mailto:otaylor@redhat.com)
Tim Janik timj@gtk.org (mailto:timj@gtk.org)
GTK is essentially an object oriented application programmers interface (API). Although written
completely in C, it is implemented using the idea of classes and callback functions (pointers to
functions).
There is also a third component called GLib which contains a few replacements for some standard calls,
as well as some additional functions for handling linked lists, etc. The replacement functions are used to
increase GTK’s portability, as some of the functions implemented here are not available or are
nonstandard on other Unixes such as g_strerror(). Some also contain enhancements to the libc versions,
such as g_malloc() that has enhanced debugging utilities.
In version 2.0, GLib has picked up the type system which forms the foundation for GTK’s class
hierarchy, the signal system which is used throughout GTK, a thread API which abstracts the different
native thread APIs of the various platforms and a facility for loading modules.
As the last component, GTK uses the Pango library for internationalized text output.
This tutorial describes the C interface to GTK. There are GTK bindings for many other languages
including C++, Guile, Perl, Python, TOM, Ada95, Objective C, Free Pascal, Eiffel, Java and C#. If you
1

Page 10
Chapter 1. Introduction
intend to use another language’s bindings to GTK, look at that binding’s documentation first. In some
cases that documentation may describe some important conventions (which you should know first) and
then refer you back to this tutorial. There are also some cross-platform APIs (such as wxWindows and
V) which use GTK as one of their target platforms; again, consult their documentation first.
If you’re developing your GTK application in C++, a few extra notes are in order. There’s a C++ binding
to GTK called GTK--, which provides a more C++-like interface to GTK; you should probably look into
this instead. If you don’t like that approach for whatever reason, there are two alternatives for using
GTK. First, you can use only the C subset of C++ when interfacing with GTK and then use the C
interface as described in this tutorial. Second, you can use GTK and C++ together by declaring all
callbacks as static functions in C++ classes, and again calling GTK using its C interface. If you choose
this last approach, you can include as the callback’s data value a pointer to the object to be manipulated
(the so-called "this" value). Selecting between these options is simply a matter of preference, since in all
three approaches you get C++ and GTK. None of these approaches requires the use of a specialized
preprocessor, so no matter what you choose you can use standard C++ with GTK.
This tutorial is an attempt to document as much as possible of GTK, but it is by no means complete. This
tutorial assumes a good understanding of C, and how to create C programs. It would be a great benefit
for the reader to have previous X programming experience, but it shouldn’t be necessary. If you are
learning GTK as your first widget set, please comment on how you found this tutorial, and what you had
trouble with. There are also C++, Objective C, ADA, Guile and other language bindings available, but I
don’t follow these.
This document is a "work in progress". Please look for updates on http://www.gtk.org/.
I would very much like to hear of any problems you have learning GTK from this document, and would
appreciate input as to how it may be improved. Please see the section on Contributing for further
information.
2

Page 11
Chapter 2. Getting Started
The first thing to do, of course, is download the GTK source and install it. You can always get the latest
version from ftp.gtk.org (ftp://ftp.gtk.org/pub/gtk). You can also view other sources of GTK information
on http://www.gtk.org/. GTK uses GNU autoconf for configuration. Once untar’d, type
./configure
--help
to see a list of options.
The GTK source distribution also contains the complete source to all of the examples used in this
tutorial, along with Makefiles to aid compilation.
To begin our introduction to GTK, we’ll start with the simplest program possible. This program will
create a 200x200 pixel window and has no way of exiting except to be killed by using the shell.
#include <gtk/gtk.h>
int main( int
argc,
char *argv[] )
{
GtkWidget *window;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_show (window);
gtk_main ();
return 0;
}
You can compile the above program with gcc using:
gcc base.c -o base ‘pkg-config --cflags --libs gtk+-2.0‘
The meaning of the unusual compilation options is explained below in Compiling Hello World.
All programs will of course include
gtk/gtk.h
which declares the variables, functions, structures, etc.
that will be used in your GTK application.
The next line:
3

Page 12
Chapter 2. Getting Started
gtk_init (&argc, &argv);
calls the function gtk_init(gint *argc, gchar ***argv) which will be called in all GTK applications. This
sets up a few things for us such as the default visual and color map and then proceeds to call gdk_init(gint
*argc, gchar ***argv). This function initializes the library for use, sets up default signal handlers, and
checks the arguments passed to your application on the command line, looking for one of the following:
--gtk-module
--g-fatal-warnings
--gtk-debug
--gtk-no-debug
--gdk-debug
--gdk-no-debug
--display
--sync
--name
--class
It removes these from the argument list, leaving anything it does not recognize for your application to
parse or ignore. This creates a set of standard arguments accepted by all GTK applications.
The next two lines of code create and display a window.
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_show (window);
The
GTK_WINDOW_TOPLEVEL
argument specifies that we want the window to undergo window manager
decoration and placement. Rather than create a window of 0x0 size, a window without children is set to
200x200 by default so you can still manipulate it.
The gtk_widget_show() function lets GTK know that we are done setting the attributes of this widget,
and that it can display it.
The last line enters the GTK main processing loop.
gtk_main ();
gtk_main() is another call you will see in every GTK application. When control reaches this point, GTK
will sleep waiting for X events (such as button or key presses), timeouts, or file IO notifications to occur.
In our simple example, however, events are ignored.
2.1. Hello World in GTK
Now for a program with a widget (a button). It’s the classic hello world a la GTK.
4

Page 13
Chapter 2. Getting Started
#include <gtk/gtk.h>
/* This is a callback function. The data arguments are ignored
* in this example. More on callbacks below. */
void hello( GtkWidget *widget,
gpointer
data )
{
g_print ("Hello World\n");
}
gint delete_event( GtkWidget *widget,
GdkEvent *event,
gpointer
data )
{
/* If you return FALSE in the "delete_event" signal handler,
* GTK will emit the "destroy" signal. Returning TRUE means
* you don’t want the window to be destroyed.
* This is useful for popping up ’are you sure you want to quit?’
* type dialogs. */
g_print ("delete event occurred\n");
/* Change TRUE to FALSE and the main window will be destroyed with
* a "delete_event". */
return TRUE;
}
/* Another callback */
void destroy( GtkWidget *widget,
gpointer
data )
{
gtk_main_quit ();
}
int main( int
argc,
char *argv[] )
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *button;
/* This is called in all GTK applications. Arguments are parsed
* from the command line and are returned to the application. */
gtk_init (&argc, &argv);
/* create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* When the window is given the "delete_event" signal (this is given
* by the window manager, usually by the "close" option, or on the
* titlebar), we ask it to call the delete_event () function
* as defined above. The data passed to the callback
5

Page 14
Chapter 2. Getting Started
* function is NULL and is ignored in the callback function. */
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
/* Here we connect the "destroy" event to a signal handler.
* This event occurs when we call gtk_widget_destroy() on the window,
* or if we return FALSE in the "delete_event" callback. */
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (destroy), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Creates a new button with the label "Hello World". */
button = gtk_button_new_with_label ("Hello World");
/* When the button receives the "clicked" signal, it will call the
* function hello() passing it NULL as its argument. The hello()
* function is defined above. */
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (hello), NULL);
/* This will cause the window to be destroyed by calling
* gtk_widget_destroy(window) when "clicked". Again, the destroy
* signal could come from here, or the window manager. */
g_signal_connect_swapped (G_OBJECT (button), "clicked",
G_CALLBACK (gtk_widget_destroy),
window);
/* This packs the button into the window (a gtk container). */
gtk_container_add (GTK_CONTAINER (window), button);
/* The final step is to display this newly created widget. */
gtk_widget_show (button);
/* and the window */
gtk_widget_show (window);
/* All GTK applications must have a gtk_main(). Control ends here
* and waits for an event to occur (like a key press or
* mouse event). */
gtk_main ();
return 0;
}
6

Page 15
Chapter 2. Getting Started
2.2. Compiling Hello World
To compile use:
gcc -Wall -g helloworld.c -o helloworld ‘pkg-config --cflags gtk+-2.0‘ \
‘pkg-config --libs gtk+-2.0‘
This uses the program
pkg-config
, which can be obtained from www.freedesktop.org
(http://www.freedesktop.org). This program reads the
.pc
which comes with GTK to determine what
compiler switches are needed to compile programs that use GTK.
pkg-config --cflags gtk+-2.0
will output a list of include directories for the compiler to look in, and
pkg-config --libs
gtk+-2.0
will output the list of libraries for the compiler to link with and the directories to find them in.
In the above example they could have been combined into a single instance, such as
pkg-config
--cflags --libs gtk+-2.0
.
Note that the type of single quote used in the compile command above is significant.
The libraries that are usually linked in are:
The GTK library (
-lgtk
), the widget library, based on top of GDK.
The GDK library (
-lgdk
), the Xlib wrapper.
The gdk-pixbuf library (
-lgdk_pixbuf
), the image manipulation library.
The Pango library (
-lpango
) for internationalized text.
The gobject library (
-lgobject
), containing the type system on which GTK is based.
The gmodule library (
-lgmodule
), which is used to load run time extensions.
The GLib library (
-lglib
), containing miscellaneous functions; only g_print() is used in this
particular example. GTK is built on top of GLib so you will always require this library. See the section
on GLib for details.
The Xlib library (
-lX11
) which is used by GDK.
The Xext library (
-lXext
). This contains code for shared memory pixmaps and other X extensions.
The math library (
-lm
). This is used by GTK for various purposes.
2.3. Theory of Signals and Callbacks
Note: In version 2.0, the signal system has been moved from GTK to GLib, therefore the functions
and types explained in this section have a "g_" prefix rather than a "gtk_" prefix. We won’t go into
details about the extensions which the GLib 2.0 signal system has relative to the GTK 1.2 signal
system.
7

Page 16
Chapter 2. Getting Started
Before we look in detail at helloworld, we’ll discuss signals and callbacks. GTK is an event driven
toolkit, which means it will sleep in gtk_main() until an event occurs and control is passed to the
appropriate function.
This passing of control is done using the idea of "signals". (Note that these signals are not the same as
the Unix system signals, and are not implemented using them, although the terminology is almost
identical.) When an event occurs, such as the press of a mouse button, the appropriate signal will be
"emitted" by the widget that was pressed. This is how GTK does most of its useful work. There are
signals that all widgets inherit, such as "destroy", and there are signals that are widget specific, such as
"toggled" on a toggle button.
To make a button perform an action, we set up a signal handler to catch these signals and call the
appropriate function. This is done by using a function such as:
gulong g_signal_connect( gpointer
*object,
const gchar
*name,
GCallback
func,
gpointer
func_data );
where the first argument is the widget which will be emitting the signal, and the second the name of the
signal you wish to catch. The third is the function you wish to be called when it is caught, and the fourth,
the data you wish to have passed to this function.
The function specified in the third argument is called a "callback function", and should generally be of
the form
void callback_func( GtkWidget *widget,
gpointer
callback_data );
where the first argument will be a pointer to the widget that emitted the signal, and the second a pointer
to the data given as the last argument to the g_signal_connect() function as shown above.
Note that the above form for a signal callback function declaration is only a general guide, as some
widget specific signals generate different calling parameters.
Another call used in the helloworld example, is:
gulong g_signal_connect_swapped( gpointer
*object,
const gchar *name,
GCallback
func,
gpointer
*slot_object );
8

Page 17
Chapter 2. Getting Started
g_signal_connect_swapped() is the same as g_signal_connect() except that the callback function only
uses one argument, a pointer to a GTK object. So when using this function to connect signals, the
callback should be of the form
void callback_func( GtkObject *object );
where the object is usually a widget. We usually don’t setup callbacks for g_signal_connect_swapped()
however. They are usually used to call a GTK function that accepts a single widget or object as an
argument, as is the case in our helloworld example.
The purpose of having two functions to connect signals is simply to allow the callbacks to have a
different number of arguments. Many functions in the GTK library accept only a single GtkWidget
pointer as an argument, so you want to use the g_signal_connect_swapped() for these, whereas for your
functions, you may need to have additional data supplied to the callbacks.
2.4. Events
In addition to the signal mechanism described above, there is a set of events that reflect the X event
mechanism. Callbacks may also be attached to these events. These events are:
event
button_press_event
button_release_event
scroll_event
motion_notify_event
delete_event
destroy_event
expose_event
key_press_event
key_release_event
enter_notify_event
leave_notify_event
configure_event
focus_in_event
focus_out_event
map_event
unmap_event
property_notify_event
selection_clear_event
selection_request_event
selection_notify_event
proximity_in_event
proximity_out_event
visibility_notify_event
client_event
no_expose_event
9

Page 18
Chapter 2. Getting Started
window_state_event
In order to connect a callback function to one of these events you use the function g_signal_connect(), as
described above, using one of the above event names as the
name
parameter. The callback function for
events has a slightly different form than that for signals:
gint callback_func( GtkWidget *widget,
GdkEvent *event,
gpointer
callback_data );
GdkEvent is a C
union
structure whose type will depend upon which of the above events has occurred.
In order for us to tell which event has been issued each of the possible alternatives has a
type
member
that reflects the event being issued. The other components of the event structure will depend upon the
type of the event. Possible values for the type are:
GDK_NOTHING
GDK_DELETE
GDK_DESTROY
GDK_EXPOSE
GDK_MOTION_NOTIFY
GDK_BUTTON_PRESS
GDK_2BUTTON_PRESS
GDK_3BUTTON_PRESS
GDK_BUTTON_RELEASE
GDK_KEY_PRESS
GDK_KEY_RELEASE
GDK_ENTER_NOTIFY
GDK_LEAVE_NOTIFY
GDK_FOCUS_CHANGE
GDK_CONFIGURE
GDK_MAP
GDK_UNMAP
GDK_PROPERTY_NOTIFY
GDK_SELECTION_CLEAR
GDK_SELECTION_REQUEST
GDK_SELECTION_NOTIFY
GDK_PROXIMITY_IN
GDK_PROXIMITY_OUT
GDK_DRAG_ENTER
GDK_DRAG_LEAVE
GDK_DRAG_MOTION
GDK_DRAG_STATUS
GDK_DROP_START
GDK_DROP_FINISHED
GDK_CLIENT_EVENT
GDK_VISIBILITY_NOTIFY
GDK_NO_EXPOSE
GDK_SCROLL
GDK_WINDOW_STATE
GDK_SETTING
10

Page 19
Chapter 2. Getting Started
So, to connect a callback function to one of these events we would use something like:
g_signal_connect (G_OBJECT (button), "button_press_event",
G_CALLBACK (button_press_callback), NULL);
This assumes that
button
is a Button widget. Now, when the mouse is over the button and a mouse
button is pressed, the function button_press_callback() will be called. This function may be declared as:
static gint button_press_callback( GtkWidget
*widget,
GdkEventButton *event,
gpointer
data );
Note that we can declare the second argument as type
GdkEventButton
as we know what type of event
will occur for this function to be called.
The value returned from this function indicates whether the event should be propagated further by the
GTK event handling mechanism. Returning TRUE indicates that the event has been handled, and that it
should not propagate further. Returning FALSE continues the normal event handling. See the section on
Advanced Event and Signal Handling for more details on this propagation process.
For details on the GdkEvent data types, see the appendix entitled GDK Event Types.
The GDK selection and drag-and-drop APIs also emit a number of events which are reflected in GTK by
the signals. See Signals on the source widget and Signals on the destination widget for details on the
signatures of the callback functions for these signals:
selection_received
selection_get
drag_begin_event
drag_end_event
drag_data_delete
drag_motion
drag_drop
drag_data_get
drag_data_received
2.5. Stepping Through Hello World
Now that we know the theory behind this, let’s clarify by walking through the example helloworld
program.
Here is the callback function that will be called when the button is "clicked". We ignore both the widget
and the data in this example, but it is not hard to do things with them. The next example will use the data
argument to tell us which button was pressed.
11

Page 20
Chapter 2. Getting Started
void hello( GtkWidget *widget,
gpointer
data )
{
g_print ("Hello World\n");
}
The next callback is a bit special. The "delete_event" occurs when the window manager sends this event
to the application. We have a choice here as to what to do about these events. We can ignore them, make
some sort of response, or simply quit the application.
The value you return in this callback lets GTK know what action to take. By returning TRUE, we let it
know that we don’t want to have the "destroy" signal emitted, keeping our application running. By
returning FALSE, we ask that "destroy" be emitted, which in turn will call our "destroy" signal handler.
gint delete_event( GtkWidget *widget,
GdkEvent *event,
gpointer
data )
{
g_print ("delete event occurred\n");
return TRUE;
}
Here is another callback function which causes the program to quit by calling gtk_main_quit(). This
function tells GTK that it is to exit from gtk_main when control is returned to it.
void destroy( GtkWidget *widget,
gpointer
data )
{
gtk_main_quit ();
}
I assume you know about the main() function... yes, as with other applications, all GTK applications will
also have one of these.
int main( int
argc,
char *argv[] )
{
This next part declares pointers to a structure of type GtkWidget. These are used below to create a
window and a button.
GtkWidget *window;
GtkWidget *button;
Here is our gtk_init() again. As before, this initializes the toolkit, and parses the arguments found on the
command line. Any argument it recognizes from the command line, it removes from the list, and
12

Page 21
Chapter 2. Getting Started
modifies argc and argv to make it look like they never existed, allowing your application to parse the
remaining arguments.
gtk_init (&argc, &argv);
Create a new window. This is fairly straightforward. Memory is allocated for the GtkWidget *window
structure so it now points to a valid structure. It sets up a new window, but it is not displayed until we call
gtk_widget_show(window) near the end of our program.
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Here are two examples of connecting a signal handler to an object, in this case, the window. Here, the
"delete_event" and "destroy" signals are caught. The first is emitted when we use the window manager to
kill the window, or when we use the gtk_widget_destroy() call passing in the window widget as the
object to destroy. The second is emitted when, in the "delete_event" handler, we return FALSE. The
G_OBJECT
and
G_CALLBACK
are macros that perform type casting and checking for us, as well as aid the
readability of the code.
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (destroy), NULL);
This next function is used to set an attribute of a container object. This just sets the window so it has a
blank area along the inside of it 10 pixels wide where no widgets will go. There are other similar
functions which we will look at in the section on Setting Widget Attributes
And again,
GTK_CONTAINER
is a macro to perform type casting.
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
This call creates a new button. It allocates space for a new GtkWidget structure in memory, initializes it,
and makes the button pointer point to it. It will have the label "Hello World" on it when displayed.
button = gtk_button_new_with_label ("Hello World");
Here, we take this button, and make it do something useful. We attach a signal handler to it so when it
emits the "clicked" signal, our hello() function is called. The data is ignored, so we simply pass in NULL
to the hello() callback function. Obviously, the "clicked" signal is emitted when we click the button with
our mouse pointer.
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (hello), NULL);
We are also going to use this button to exit our program. This will illustrate how the "destroy" signal may
come from either the window manager, or our program. When the button is "clicked", same as above, it
13

Page 22
Chapter 2. Getting Started
calls the first hello() callback function, and then this one in the order they are set up. You may have as
many callback functions as you need, and all will be executed in the order you connected them. Because
the gtk_widget_destroy() function accepts only a GtkWidget *widget as an argument, we use the
g_signal_connect_swapped() function here instead of straight g_signal_connect().
g_signal_connect_swapped (G_OBJECT (button), "clicked",
G_CALLBACK (gtk_widget_destroy),
G_OBJECT (window));
This is a packing call, which will be explained in depth later on in Packing Widgets. But it is fairly easy
to understand. It simply tells GTK that the button is to be placed in the window where it will be
displayed. Note that a GTK container can only contain one widget. There are other widgets, that are
described later, which are designed to layout multiple widgets in various ways.
gtk_container_add (GTK_CONTAINER (window), button);
Now we have everything set up the way we want it to be. With all the signal handlers in place, and the
button placed in the window where it should be, we ask GTK to "show" the widgets on the screen. The
window widget is shown last so the whole window will pop up at once rather than seeing the window
pop up, and then the button form inside of it. Although with such a simple example, you’d never notice.
gtk_widget_show (button);
gtk_widget_show (window);
And of course, we call gtk_main() which waits for events to come from the X server and will call on the
widgets to emit signals when these events come.
gtk_main ();
And the final return. Control returns here after gtk_quit() is called.
return 0;
Now, when we click the mouse button on a GTK button, the widget emits a "clicked" signal. In order for
us to use this information, our program sets up a signal handler to catch that signal, which dispatches the
function of our choice. In our example, when the button we created is "clicked", the hello() function is
called with a NULL argument, and then the next handler for this signal is called. This calls the
gtk_widget_destroy() function, passing it the window widget as its argument, destroying the window
widget. This causes the window to emit the "destroy" signal, which is caught, and calls our destroy()
callback function, which simply exits GTK.
Another course of events is to use the window manager to kill the window, which will cause the
"delete_event" to be emitted. This will call our "delete_event" handler. If we return TRUE here, the
window will be left as is and nothing will happen. Returning FALSE will cause GTK to emit the
"destroy" signal which of course calls the "destroy" callback, exiting GTK.
14

Page 23
Chapter 3. Moving On
3.1. Data Types
There are a few things you probably noticed in the previous examples that need explaining. The gint,
gchar, etc. that you see are typedefs to int and char, respectively, that are part of the GLib system. This is
done to get around that nasty dependency on the size of simple data types when doing calculations.
A good example is "gint32" which will be typedef’d to a 32 bit integer for any given platform, whether it
be the 64 bit alpha, or the 32 bit i386. The typedefs are very straightforward and intuitive. They are all
defined in
glib/glib.h
(which gets included from
gtk.h
).
You’ll also notice GTK’s ability to use GtkWidget when the function calls for a GtkObject. GTK is an
object oriented design, and a widget is an object.
3.2. More on Signal Handlers
Lets take another look at the gtk_signal_connect() declaration.
gulong g_signal_connect( gpointer object,
const gchar *name,
GCallback func,
gpointer func_data );
Notice the gulong return value? This is a tag that identifies your callback function. As stated above, you
may have as many callbacks per signal and per object as you need, and each will be executed in turn, in
the order they were attached.
This tag allows you to remove this callback from the list by using:
void g_signal_handler_disconnect( gpointer object,
gulong
id );
So, by passing in the widget you wish to remove the handler from, and the tag returned by one of the
signal_connect functions, you can disconnect a signal handler.
You can also temporarily disable signal handlers with the g_signal_handler_block() and
g_signal_handler_unblock() family of functions.
void g_signal_handler_block( gpointer object,
gulong
id );
15

Page 24
Chapter 3. Moving On
void g_signal_handlers_block_by_func( gpointer object,
GCallback func,
gpointer data );
void g_signal_handler_unblock( gpointer object,
gulong
id );
void g_signal_handlers_unblock_by_func( gpointer object,
GCallback func,
gpointer data );
3.3. An Upgraded Hello World
Let’s take a look at a slightly improved helloworld with better examples of callbacks. This will also
introduce us to our next topic, packing widgets.
#include <gtk/gtk.h>
/* Our new improved callback. The data passed to this function
* is printed to stdout. */
void callback( GtkWidget *widget,
gpointer
data )
{
g_print ("Hello again - %s was pressed\n", (gchar *) data);
}
/* another callback */
gint delete_event( GtkWidget *widget,
GdkEvent *event,
gpointer
data )
{
gtk_main_quit ();
return FALSE;
}
int main( int
argc,
char *argv[] )
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *button;
GtkWidget *box1;
/* This is called in all GTK applications. Arguments are parsed
* from the command line and are returned to the application. */
gtk_init (&argc, &argv);
/* Create a new window */
16

Page 25
Chapter 3. Moving On
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* This is a new call, which just sets the title of our
* new window to "Hello Buttons!" */
gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
/* Here we just set a handler for delete_event that immediately
* exits GTK. */
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* We create a box to pack widgets into. This is described in detail
* in the "packing" section. The box is not really visible, it
* is just used as a tool to arrange widgets. */
box1 = gtk_hbox_new (FALSE, 0);
/* Put the box into the main window. */
gtk_container_add (GTK_CONTAINER (window), box1);
/* Creates a new button with the label "Button 1". */
button = gtk_button_new_with_label ("Button 1");
/* Now when the button is clicked, we call the "callback" function
* with a pointer to "button 1" as its argument */
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (callback), "button 1");
/* Instead of gtk_container_add, we pack this button into the invisible
* box, which has been packed into the window. */
gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0);
/* Always remember this step, this tells GTK that our preparation for
* this button is complete, and it can now be displayed. */
gtk_widget_show (button);
/* Do these same steps again to create a second button */
button = gtk_button_new_with_label ("Button 2");
/* Call the same callback function with a different argument,
* passing a pointer to "button 2" instead. */
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (callback), "button 2");
gtk_box_pack_start(GTK_BOX (box1), button, TRUE, TRUE, 0);
/* The order in which we show the buttons is not really important, but I
* recommend showing the window last, so it all pops up at once. */
gtk_widget_show (button);
gtk_widget_show (box1);
17

Page 26
Chapter 3. Moving On
gtk_widget_show (window);
/* Rest in gtk_main and wait for the fun to begin! */
gtk_main ();
return 0;
}
Compile this program using the same linking arguments as our first example. You’ll notice this time
there is no easy way to exit the program, you have to use your window manager or command line to kill
it. A good exercise for the reader would be to insert a third "Quit" button that will exit the program. You
may also wish to play with the options to gtk_box_pack_start() while reading the next section. Try
resizing the window, and observe the behavior.
18

Page 27
Chapter 4. Packing Widgets
When creating an application, you’ll want to put more than one widget inside a window. Our first
helloworld example only used one widget so we could simply use a gtk_container_add() call to "pack"
the widget into the window. But when you want to put more than one widget into a window, how do you
control where that widget is positioned? This is where packing comes in.
4.1. Theory of Packing Boxes
Most packing is done by creating boxes. These are invisible widget containers that we can pack our
widgets into which come in two forms, a horizontal box, and a vertical box. When packing widgets into a
horizontal box, the objects are inserted horizontally from left to right or right to left depending on the
call used. In a vertical box, widgets are packed from top to bottom or vice versa. You may use any
combination of boxes inside or beside other boxes to create the desired effect.
To create a new horizontal box, we use a call to gtk_hbox_new(), and for vertical boxes, gtk_vbox_new().
The gtk_box_pack_start() and gtk_box_pack_end() functions are used to place objects inside of these
containers. The gtk_box_pack_start() function will start at the top and work its way down in a vbox, and
pack left to right in an hbox. gtk_box_pack_end() will do the opposite, packing from bottom to top in a
vbox, and right to left in an hbox. Using these functions allows us to right justify or left justify our
widgets and may be mixed in any way to achieve the desired effect. We will use gtk_box_pack_start() in
most of our examples. An object may be another container or a widget. In fact, many widgets are
actually containers themselves, including the button, but we usually only use a label inside a button.
By using these calls, GTK knows where you want to place your widgets so it can do automatic resizing
and other nifty things. There are also a number of options as to how your widgets should be packed. As
you can imagine, this method gives us a quite a bit of flexibility when placing and creating widgets.
4.2. Details of Boxes
Because of this flexibility, packing boxes in GTK can be confusing at first. There are a lot of options, and
it’s not immediately obvious how they all fit together. In the end, however, there are basically five
different styles.
Each line contains one horizontal box (hbox) with several buttons. The call to gtk_box_pack is shorthand
for the call to pack each of the buttons into the hbox. Each of the buttons is packed into the hbox the
same way (i.e., same arguments to the gtk_box_pack_start() function).
This is the declaration of the gtk_box_pack_start() function.
19

Page 28
Chapter 4. Packing Widgets
void gtk_box_pack_start( GtkBox
*box,
GtkWidget *child,
gboolean
expand,
gboolean
fill,
guint
padding );
The first argument is the box you are packing the object into, the second is the object. The objects will all
be buttons for now, so we’ll be packing buttons into boxes.
The expand argument to gtk_box_pack_start() and gtk_box_pack_end() controls whether the widgets are
laid out in the box to fill in all the extra space in the box so the box is expanded to fill the area allotted to
it (TRUE); or the box is shrunk to just fit the widgets (FALSE). Setting expand to FALSE will allow you
to do right and left justification of your widgets. Otherwise, they will all expand to fit into the box, and
the same effect could be achieved by using only one of gtk_box_pack_start() or gtk_box_pack_end().
The fill argument to the gtk_box_pack functions control whether the extra space is allocated to the
objects themselves (TRUE), or as extra padding in the box around these objects (FALSE). It only has an
effect if the expand argument is also TRUE.
When creating a new box, the function looks like this:
GtkWidget *gtk_hbox_new ( gboolean homogeneous,
gint
spacing );
The homogeneous argument to gtk_hbox_new() (and the same for gtk_vbox_new()) controls whether
each object in the box has the same size (i.e., the same width in an hbox, or the same height in a vbox). If
it is set, the gtk_box_pack() routines function essentially as if the
expand
argument was always turned
on.
What’s the difference between spacing (set when the box is created) and padding (set when elements are
packed)? Spacing is added between objects, and padding is added on either side of an object. The
following figure should make it clearer:
Here is the code used to create the above images. I’ve commented it fairly heavily so I hope you won’t
have any problems following it. Compile it yourself and play with it.
4.3. Packing Demonstration Program
#include <stdio.h>
#include <stdlib.h>
#include "gtk/gtk.h"
gint delete_event( GtkWidget *widget,
20

Page 29
Chapter 4. Packing Widgets
GdkEvent *event,
gpointer
data )
{
gtk_main_quit ();
return FALSE;
}
/* Make a new hbox filled with button-labels. Arguments for the
* variables we’re interested are passed in to this function.
* We do not show the box, but do show everything inside. */
GtkWidget *make_box( gboolean homogeneous,
gint
spacing,
gboolean expand,
gboolean fill,
guint
padding )
{
GtkWidget *box;
GtkWidget *button;
char padstr[80];
/* Create a new hbox with the appropriate homogeneous
* and spacing settings */
box = gtk_hbox_new (homogeneous, spacing);
/* Create a series of buttons with the appropriate settings */
button = gtk_button_new_with_label ("gtk_box_pack");
gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
gtk_widget_show (button);
button = gtk_button_new_with_label ("(box,");
gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
gtk_widget_show (button);
button = gtk_button_new_with_label ("button,");
gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
gtk_widget_show (button);
/* Create a button with the label depending on the value of
* expand. */
if (expand == TRUE)
button = gtk_button_new_with_label ("TRUE,");
else
button = gtk_button_new_with_label ("FALSE,");
gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
gtk_widget_show (button);
/* This is the same as the button creation for "expand"
* above, but uses the shorthand form. */
button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
gtk_widget_show (button);
21

Page 30
Chapter 4. Packing Widgets
sprintf (padstr, "%d);", padding);
button = gtk_button_new_with_label (padstr);
gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
gtk_widget_show (button);
return box;
}
int main( int
argc,
char *argv[])
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *box1;
GtkWidget *box2;
GtkWidget *separator;
GtkWidget *label;
GtkWidget *quitbox;
int which;
/* Our init, don’t forget this! :) */
gtk_init (&argc, &argv);
if (argc != 2) {
fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
/* This just does cleanup in GTK and exits with an exit status of 1. */
exit (1);
}
which = atoi (argv[1]);
/* Create our window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* You should always remember to connect the delete_event signal
* to the main window. This is very important for proper intuitive
* behavior */
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* We create a vertical box (vbox) to pack the horizontal boxes into.
* This allows us to stack the horizontal boxes filled with buttons one
* on top of the other in this vbox. */
box1 = gtk_vbox_new (FALSE, 0);
/* which example to show. These correspond to the pictures above. */
switch (which) {
case 1:
/* create a new label. */
label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
22

Page 31
Chapter 4. Packing Widgets
/* Align the label to the left side. We’ll discuss this function and
* others in the section on Widget Attributes. */
gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
/* Pack the label into the vertical box (vbox box1). Remember that
* widgets added to a vbox will be packed one on top of the other in
* order. */
gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
/* Show the label */
gtk_widget_show (label);
/* Call our make box function - homogeneous = FALSE, spacing = 0,
* expand = FALSE, fill = FALSE, padding = 0 */
box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
gtk_widget_show (box2);
/* Call our make box function - homogeneous = FALSE, spacing = 0,
* expand = TRUE, fill = FALSE, padding = 0 */
box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
gtk_widget_show (box2);
/* Args are: homogeneous, spacing, expand, fill, padding */
box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
gtk_widget_show (box2);
/* Creates a separator, we’ll learn more about these later,
* but they are quite simple. */
separator = gtk_hseparator_new ();
/* Pack the separator into the vbox. Remember each of these
* widgets is being packed into a vbox, so they’ll be stacked
* vertically. */
gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
gtk_widget_show (separator);
/* Create another new label, and show it. */
label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
gtk_widget_show (label);
/* Args are: homogeneous, spacing, expand, fill, padding */
box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
gtk_widget_show (box2);
/* Args are: homogeneous, spacing, expand, fill, padding */
box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
23

Page 32
Chapter 4. Packing Widgets
gtk_widget_show (box2);
/* Another new separator. */
separator = gtk_hseparator_new ();
/* The last 3 arguments to gtk_box_pack_start are:
* expand, fill, padding. */
gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
gtk_widget_show (separator);
break;
case 2:
/* Create a new label, remember box1 is a vbox as created
* near the beginning of main() */
label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
gtk_widget_show (label);
/* Args are: homogeneous, spacing, expand, fill, padding */
box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
gtk_widget_show (box2);
/* Args are: homogeneous, spacing, expand, fill, padding */
box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
gtk_widget_show (box2);
separator = gtk_hseparator_new ();
/* The last 3 arguments to gtk_box_pack_start are:
* expand, fill, padding. */
gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
gtk_widget_show (separator);
label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
gtk_widget_show (label);
/* Args are: homogeneous, spacing, expand, fill, padding */
box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
gtk_widget_show (box2);
/* Args are: homogeneous, spacing, expand, fill, padding */
box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
gtk_widget_show (box2);
separator = gtk_hseparator_new ();
/* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
24

Page 33
Chapter 4. Packing Widgets
gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
gtk_widget_show (separator);
break;
case 3:
/* This demonstrates the ability to use gtk_box_pack_end() to
* right justify widgets. First, we create a new box as before. */
box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
/* Create the label that will be put at the end. */
label = gtk_label_new ("end");
/* Pack it using gtk_box_pack_end(), so it is put on the right
* side of the hbox created in the make_box() call. */
gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
/* Show the label. */
gtk_widget_show (label);
/* Pack box2 into box1 (the vbox remember ? :) */
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
gtk_widget_show (box2);
/* A separator for the bottom. */
separator = gtk_hseparator_new ();
/* This explicitly sets the separator to 400 pixels wide by 5 pixels
* high. This is so the hbox we created will also be 400 pixels wide,
* and the "end" label will be separated from the other labels in the
* hbox. Otherwise, all the widgets in the hbox would be packed as
* close together as possible. */
gtk_widget_set_size_request (separator, 400, 5);
/* pack the separator into the vbox (box1) created near the start
* of main() */
gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
gtk_widget_show (separator);
}
/* Create another new hbox.. remember we can use as many as we need! */
quitbox = gtk_hbox_new (FALSE, 0);
/* Our quit button. */
button = gtk_button_new_with_label ("Quit");
/* Setup the signal to terminate the program when the button is clicked */
g_signal_connect_swapped (G_OBJECT (button), "clicked",
G_CALLBACK (gtk_main_quit),
window);
/* Pack the button into the quitbox.
* The last 3 arguments to gtk_box_pack_start are:
* expand, fill, padding. */
gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
/* pack the quitbox into the vbox (box1) */
gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
25

Page 34
Chapter 4. Packing Widgets
/* Pack the vbox (box1) which now contains all our widgets, into the
* main window. */
gtk_container_add (GTK_CONTAINER (window), box1);
/* And show everything left */
gtk_widget_show (button);
gtk_widget_show (quitbox);
gtk_widget_show (box1);
/* Showing the window last so everything pops up at once. */
gtk_widget_show (window);
/* And of course, our main function. */
gtk_main ();
/* Control returns here when gtk_main_quit() is called, but not when
* exit() is used. */
return 0;
}
4.4. Packing Using Tables
Let’s take a look at another way of packing - Tables. These can be extremely useful in certain situations.
Using tables, we create a grid that we can place widgets in. The widgets may take up as many spaces as
we specify.
The first thing to look at, of course, is the gtk_table_new() function:
GtkWidget *gtk_table_new( guint
rows,
guint
columns,
gboolean homogeneous );
The first argument is the number of rows to make in the table, while the second, obviously, is the number
of columns.
The homogeneous argument has to do with how the table’s boxes are sized. If homogeneous is TRUE,
the table boxes are resized to the size of the largest widget in the table. If homogeneous is FALSE, the
size of a table boxes is dictated by the tallest widget in its same row, and the widest widget in its column.
The rows and columns are laid out from 0 to n, where n was the number specified in the call to
gtk_table_new. So, if you specify rows = 2 and columns = 2, the layout would look something like this:
0
1
2
0+----------+----------+
26

Page 35
Chapter 4. Packing Widgets
|
|
|
1+----------+----------+
|
|
|
2+----------+----------+
Note that the coordinate system starts in the upper left hand corner. To place a widget into a box, use the
following function:
void gtk_table_attach( GtkTable
*table,
GtkWidget
*child,
guint
left_attach,
guint
right_attach,
guint
top_attach,
guint
bottom_attach,
GtkAttachOptions xoptions,
GtkAttachOptions yoptions,
guint
xpadding,
guint
ypadding );
The first argument ("table") is the table you’ve created and the second ("child") the widget you wish to
place in the table.
The left and right attach arguments specify where to place the widget, and how many boxes to use. If you
want a button in the lower right table entry of our 2x2 table, and want it to fill that entry only, left_attach
would be = 1, right_attach = 2, top_attach = 1, bottom_attach = 2.
Now, if you wanted a widget to take up the whole top row of our 2x2 table, you’d use left_attach = 0,
right_attach = 2, top_attach = 0, bottom_attach = 1.
The xoptions and yoptions are used to specify packing options and may be bitwise OR’ed together to
allow multiple options.
These options are:
GTK_FILL
If the table box is larger than the widget, and
GTK_FILL
is specified, the widget will expand to use
all the room available.
GTK_SHRINK
If the table widget was allocated less space then was requested (usually by the user resizing the
window), then the widgets would normally just be pushed off the bottom of the window and
disappear. If
GTK_SHRINK
is specified, the widgets will shrink with the table.
GTK_EXPAND
This will cause the table to expand to use up any remaining space in the window.
27

Page 36
Chapter 4. Packing Widgets
Padding is just like in boxes, creating a clear area around the widget specified in pixels.
gtk_table_attach() has a lot of options. So, there’s a shortcut:
void gtk_table_attach_defaults( GtkTable *table,
GtkWidget *widget,
guint
left_attach,
guint
right_attach,
guint
top_attach,
guint
bottom_attach );
The X and Y options default to
GTK_FILL | GTK_EXPAND
, and X and Y padding are set to 0. The rest
of the arguments are identical to the previous function.
We also have gtk_table_set_row_spacing() and gtk_table_set_col_spacing(). These places spacing
between the rows at the specified row or column.
void gtk_table_set_row_spacing( GtkTable *table,
guint
row,
guint
spacing );
and
void gtk_table_set_col_spacing ( GtkTable *table,
guint
column,
guint
spacing );
Note that for columns, the space goes to the right of the column, and for rows, the space goes below the
row.
You can also set a consistent spacing of all rows and/or columns with:
void gtk_table_set_row_spacings( GtkTable *table,
guint
spacing );
And,
void gtk_table_set_col_spacings( GtkTable *table,
guint
spacing );
Note that with these calls, the last row and last column do not get any spacing.
28

Page 37
Chapter 4. Packing Widgets
4.5. Table Packing Example
Here we make a window with three buttons in a 2x2 table. The first two buttons will be placed in the
upper row. A third, quit button, is placed in the lower row, spanning both columns. Which means it
should look something like this:
Here’s the source code:
#include <gtk/gtk.h>
/* Our callback.
* The data passed to this function is printed to stdout */
void callback( GtkWidget *widget,
gpointer
data )
{
g_print ("Hello again - %s was pressed\n", (char *) data);
}
/* This callback quits the program */
gint delete_event( GtkWidget *widget,
GdkEvent *event,
gpointer
data )
{
gtk_main_quit ();
return FALSE;
}
int main( int
argc,
char *argv[] )
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *table;
gtk_init (&argc, &argv);
/* Create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* Set the window title */
gtk_window_set_title (GTK_WINDOW (window), "Table");
/* Set a handler for delete_event that immediately
* exits GTK. */
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (delete_event), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 20);
29

Page 38
Chapter 4. Packing Widgets
/* Create a 2x2 table */
table = gtk_table_new (2, 2, TRUE);
/* Put the table in the main window */
gtk_container_add (GTK_CONTAINER (window), table);
/* Create first button */
button = gtk_button_new_with_label ("button 1");
/* When the button is clicked, we call the "callback" function
* with a pointer to "button 1" as its argument */
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (callback), (gpointer) "button 1");
/* Insert button 1 into the upper left quadrant of the table */
gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 1, 0, 1);
gtk_widget_show (button);
/* Create second button */
button = gtk_button_new_with_label ("button 2");
/* When the button is clicked, we call the "callback" function
* with a pointer to "button 2" as its argument */
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (callback), (gpointer) "button 2");
/* Insert button 2 into the upper right quadrant of the table */
gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, 0, 1);
gtk_widget_show (button);
/* Create "Quit" button */
button = gtk_button_new_with_label ("Quit");
/* When the button is clicked, we call the "delete_event" function
* and the program exits */
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (delete_event), NULL);
/* Insert the quit button into the both
* lower quadrants of the table */
gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 2, 1, 2);
gtk_widget_show (button);
gtk_widget_show (table);
gtk_widget_show (window);
gtk_main ();
return 0;
30

Page 39
Chapter 4. Packing Widgets
}
31

Page 40
Chapter 5. Widget Overview
The general steps to creating a widget in GTK are:
1. gtk_*_new() - one of various functions to create a new widget. These are all detailed in this section.
2. Connect all signals and events we wish to use to the appropriate handlers.
3. Set the attributes of the widget.
4. Pack the widget into a container using the appropriate call such as gtk_container_add() or
gtk_box_pack_start().
5. gtk_widget_show() the widget.
gtk_widget_show() lets GTK know that we are done setting the attributes of the widget, and it is ready to
be displayed. You may also use gtk_widget_hide to make it disappear again. The order in which you
show the widgets is not important, but I suggest showing the window last so the whole window pops up
at once rather than seeing the individual widgets come up on the screen as they’re formed. The children
of a widget (a window is a widget too) will not be displayed until the window itself is shown using the
gtk_widget_show() function.
5.1. Casting
You’ll notice as you go on that GTK uses a type casting system. This is always done using macros that
both test the ability to cast the given item, and perform the cast. Some common ones you will see are:
G_OBJECT (object)
GTK_WIDGET (widget)
GTK_OBJECT (object)
GTK_SIGNAL_FUNC (function)
GTK_CONTAINER (container)
GTK_WINDOW (window)
GTK_BOX (box)
These are all used to cast arguments in functions. You’ll see them in the examples, and can usually tell
when to use them simply by looking at the function’s declaration.
As you can see below in the class hierarchy, all GtkWidgets are derived from the GObject base class.
This means you can use a widget in any place the function asks for an object - simply use the
G_OBJECT()
macro.
For example:
g_signal_connect( G_OBJECT (button), "clicked",
G_CALLBACK (callback_function), callback_data);
32

Page 41
Chapter 5. Widget Overview
This casts the button into an object, and provides a cast for the function pointer to the callback.
Many widgets are also containers. If you look in the class hierarchy below, you’ll notice that many
widgets derive from the Container class. Any one of these widgets may be used with the
GTK_CONTAINER
macro to pass them to functions that ask for containers.
Unfortunately, these macros are not extensively covered in the tutorial, but I recommend taking a look
through the GTK header files or the GTK API reference manual. It can be very educational. In fact, it’s
not difficult to learn how a widget works just by looking at the function declarations.
5.2. Widget Hierarchy
For your reference, here is the class hierarchy tree used to implement widgets. (Deprecated widgets and
auxiliary classes have been omitted.)
GObject
|
GtkObject
+GtkWidget
| +GtkMisc
| | +GtkLabel
| | | ‘GtkAccelLabel
| | +GtkArrow
| | ‘GtkImage
| +GtkContainer
| | +GtkBin
| | | +GtkAlignment
| | | +GtkFrame
| | | | ‘GtkAspectFrame
| | | +GtkButton
| | | | +GtkToggleButton
| | | | | ‘GtkCheckButton
| | | | |
‘GtkRadioButton
| | | | ‘GtkOptionMenu
| | | +GtkItem
| | | | +GtkMenuItem
| | | |
+GtkCheckMenuItem
| | | |
| ‘GtkRadioMenuItem
| | | |
+GtkImageMenuItem
| | | |
+GtkSeparatorMenuItem
| | | |
‘GtkTearoffMenuItem
| | | +GtkWindow
| | | | +GtkDialog
| | | | | +GtkColorSelectionDialog
| | | | | +GtkFileSelection
| | | | | +GtkFontSelectionDialog
| | | | | +GtkInputDialog
| | | | | ‘GtkMessageDialog
| | | | ‘GtkPlug
33

Page 42
Chapter 5. Widget Overview
| | | +GtkEventBox
| | | +GtkHandleBox
| | | +GtkScrolledWindow
| | | ‘GtkViewport
| | +GtkBox
| | | +GtkButtonBox
| | | | +GtkHButtonBox
| | | | ‘GtkVButtonBox
| | | +GtkVBox
| | | | +GtkColorSelection
| | | | +GtkFontSelection
| | | | ‘GtkGammaCurve
| | | ‘GtkHBox
| | |
+GtkCombo
| | |
‘GtkStatusbar
| | +GtkFixed
| | +GtkPaned
| | | +GtkHPaned
| | | ‘GtkVPaned
| | +GtkLayout
| | +GtkMenuShell
| | | +GtkMenuBar
| | | ‘GtkMenu
| | +GtkNotebook
| | +GtkSocket
| | +GtkTable
| | +GtkTextView
| | +GtkToolbar
| | ‘GtkTreeView
| +GtkCalendar
| +GtkDrawingArea
| | ‘GtkCurve
| +GtkEditable
| | +GtkEntry
| |
‘GtkSpinButton
| +GtkRuler
| | +GtkHRuler
| | ‘GtkVRuler
| +GtkRange
| | +GtkScale
| | | +GtkHScale
| | | ‘GtkVScale
| | ‘GtkScrollbar
| |
+GtkHScrollbar
| |
‘GtkVScrollbar
| +GtkSeparator
| | +GtkHSeparator
| | ‘GtkVSeparator
| +GtkInvisible
| +GtkPreview
| ‘GtkProgressBar
+GtkAdjustment
+GtkCellRenderer
34

Page 43
Chapter 5. Widget Overview
| +GtkCellRendererPixbuf
| +GtkCellRendererText
| +GtkCellRendererToggle
+GtkItemFactory
+GtkTooltips
‘GtkTreeViewColumn
5.3. Widgets Without Windows
The following widgets do not have an associated window. If you want to capture events, you’ll have to
use the EventBox. See the section on the EventBox widget.
GtkAlignment
GtkArrow
GtkBin
GtkBox
GtkButton
GtkCheckButton
GtkFixed
GtkImage
GtkLabel
GtkMenuItem
GtkNotebook
GtkPaned
GtkRadioButton
GtkRange
GtkScrolledWindow
GtkSeparator
GtkTable
GtkToolbar
GtkAspectFrame
GtkFrame
GtkVBox
GtkHBox
GtkVSeparator
GtkHSeparator
We’ll further our exploration of GTK by examining each widget in turn, creating a few simple functions
to display them. Another good source is the
testgtk
program that comes with GTK. It can be found in
tests/testgtk.c
.
35

Page 44
Chapter 6. The Button Widget
6.1. Normal Buttons
We’ve almost seen all there is to see of the button widget. It’s pretty simple. There is however more than
one way to create a button. You can use the gtk_button_new_with_label() or
gtk_button_new_with_mnemonic() to create a button with a label, use gtk_button_new_from_stock() to
create a button containing the image and text from a stock item or use gtk_button_new() to create a blank
button. It’s then up to you to pack a label or pixmap into this new button. To do this, create a new box,
and then pack your objects into this box using the usual gtk_box_pack_start(), and then use
gtk_container_add() to pack the box into the button.
Here’s an example of using gtk_button_new() to create a button with a image and a label in it. I’ve
broken up the code to create a box from the rest so you can use it in your programs. There are further
examples of using images later in the tutorial.
#include <stdlib.h>
#include <gtk/gtk.h>
/* Create a new hbox with an image and a label packed into it
* and return the box. */
GtkWidget *xpm_label_box( gchar
*xpm_filename,
gchar
*label_text )
{
GtkWidget *box;
GtkWidget *label;
GtkWidget *image;
/* Create box for image and label */
box = gtk_hbox_new (FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (box), 2);
/* Now on to the image stuff */
image = gtk_image_new_from_file (xpm_filename);
/* Create a label for the button */
label = gtk_label_new (label_text);
/* Pack the image and label into the box */
gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 3);
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 3);
gtk_widget_show (image);
gtk_widget_show (label);
return box;
36

Page 45
Chapter 6. The Button Widget
}
/* Our usual callback function */
void callback( GtkWidget *widget,
gpointer
data )
{
g_print ("Hello again - %s was pressed\n", (char *) data);
}
int main( int
argc,
char *argv[] )
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *button;
GtkWidget *box;
gtk_init (&argc, &argv);
/* Create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Pixmap’d Buttons!");
/* It’s a good idea to do this for all windows. */
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (gtk_main_quit), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Create a new button */
button = gtk_button_new ();
/* Connect the "clicked" signal of the button to our callback */
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (callback), (gpointer) "cool button");
/* This calls our box creating function */
box = xpm_label_box ("info.xpm", "cool button");
/* Pack and show all our widgets */
gtk_widget_show (box);
gtk_container_add (GTK_CONTAINER (button), box);
gtk_widget_show (button);
gtk_container_add (GTK_CONTAINER (window), button);
37

Page 46
Chapter 6. The Button Widget
gtk_widget_show (window);
/* Rest in gtk_main and wait for the fun to begin! */
gtk_main ();
return 0;
}
The xpm_label_box() function could be used to pack images and labels into any widget that can be a
container.
The Button widget has the following signals:
pressed
- emitted when pointer button is pressed within Button widget
released
- emitted when pointer button is released within Button widget
clicked
- emitted when pointer button is pressed and then released within Button widget
enter
- emitted when pointer enters Button widget
leave
- emitted when pointer leaves Button widget
6.2. Toggle Buttons
Toggle buttons are derived from normal buttons and are very similar, except they will always be in one of
two states, alternated by a click. They may be depressed, and when you click again, they will pop back
up. Click again, and they will pop back down.
Toggle buttons are the basis for check buttons and radio buttons, as such, many of the calls used for
toggle buttons are inherited by radio and check buttons. I will point these out when we come to them.
Creating a new toggle button:
GtkWidget *gtk_toggle_button_new( void );
GtkWidget *gtk_toggle_button_new_with_label( const gchar *label );
GtkWidget *gtk_toggle_button_new_with_mnemonic( const gchar *label );
As you can imagine, these work identically to the normal button widget calls. The first creates a blank
toggle button, and the last two, a button with a label widget already packed into it. The _mnemonic()
variant additionally parses the label for ’_’-prefixed mnemonic characters.
To retrieve the state of the toggle widget, including radio and check buttons, we use a construct as shown
in our example below. This tests the state of the toggle button, by accessing the
active
field of the
toggle widget’s structure, after first using the
GTK_TOGGLE_BUTTON
macro to cast the widget pointer
38

Page 47
Chapter 6. The Button Widget
into a toggle widget pointer. The signal of interest to us emitted by toggle buttons (the toggle button,
check button, and radio button widgets) is the "toggled" signal. To check the state of these buttons, set up
a signal handler to catch the toggled signal, and access the structure to determine its state. The callback
will look something like:
void toggle_button_callback (GtkWidget *widget, gpointer data)
{
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
{
/* If control reaches here, the toggle button is down */
} else {
/* If control reaches here, the toggle button is up */
}
}
To force the state of a toggle button, and its children, the radio and check buttons, use this function:
void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
gboolean
is_active );
The above call can be used to set the state of the toggle button, and its children the radio and check
buttons. Passing in your created button as the first argument, and a TRUE or FALSE for the second state
argument to specify whether it should be down (depressed) or up (released). Default is up, or FALSE.
Note that when you use the gtk_toggle_button_set_active() function, and the state is actually changed, it
causes the "clicked" and "toggled" signals to be emitted from the button.
gboolean gtk_toggle_button_get_active (GtkToggleButton *toggle_button);
This returns the current state of the toggle button as a boolean TRUE/FALSE value.
6.3. Check Buttons
Check buttons inherit many properties and functions from the the toggle buttons above, but look a little
different. Rather than being buttons with text inside them, they are small squares with the text to the right
of them. These are often used for toggling options on and off in applications.
The creation functions are similar to those of the normal button.
GtkWidget *gtk_check_button_new( void );
GtkWidget *gtk_check_button_new_with_label ( const gchar *label );
GtkWidget *gtk_check_button_new_with_mnemonic ( const gchar *label );
39

Page 48
Chapter 6. The Button Widget
The gtk_check_button_new_with_label() function creates a check button with a label beside it.
Checking the state of the check button is identical to that of the toggle button.
6.4. Radio Buttons
Radio buttons are similar to check buttons except they are grouped so that only one may be
selected/depressed at a time. This is good for places in your application where you need to select from a
short list of options.
Creating a new radio button is done with one of these calls:
GtkWidget *gtk_radio_button_new( GSList *group );
GtkWidget *gtk_radio_button_new_from_widget( GtkRadioButton *group );
GtkWidget *gtk_radio_button_new_with_label( GSList *group,
const gchar *label );
GtkWidget* gtk_radio_button_new_with_label_from_widget( GtkRadioButton *group,
const gchar
*label );
GtkWidget *gtk_radio_button_new_with_mnemonic( GSList *group,
const gchar *label );
GtkWidget *gtk_radio_button_new_with_mnemonic_from_widget( GtkRadioButton *group,
const gchar *label );
You’ll notice the extra argument to these calls. They require a group to perform their duty properly. The
first call to gtk_radio_button_new() or gtk_radio_button_new_with_label() should pass NULL as the first
argument. Then create a group using:
GSList *gtk_radio_button_get_group( GtkRadioButton *radio_button );
The important thing to remember is that gtk_radio_button_get_group() must be called for each new
button added to the group, with the previous button passed in as an argument. The result is then passed
into the next call to gtk_radio_button_new() or gtk_radio_button_new_with_label(). This allows a chain
of buttons to be established. The example below should make this clear.
You can shorten this slightly by using the following syntax, which removes the need for a variable to
hold the list of buttons:
button2 = gtk_radio_button_new_with_label(
gtk_radio_button_get_group (GTK_RADIO_BUTTON (button1)),
"button2");
40

Page 49
Chapter 6. The Button Widget
The _from_widget() variants of the creation functions allow you to shorten this further, by omitting the
gtk_radio_button_get_group() call. This form is used in the example to create the third button:
button2 = gtk_radio_button_new_with_label_from_widget(
GTK_RADIO_BUTTON (button1),
"button2");
It is also a good idea to explicitly set which button should be the default depressed button with:
void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
gboolean
state );
This is described in the section on toggle buttons, and works in exactly the same way. Once the radio
buttons are grouped together, only one of the group may be active at a time. If the user clicks on one
radio button, and then on another, the first radio button will first emit a "toggled" signal (to report
becoming inactive), and then the second will emit its "toggled" signal (to report becoming active).
The following example creates a radio button group with three buttons.
#include <glib.h>
#include <gtk/gtk.h>
gint close_application( GtkWidget *widget,
GdkEvent *event,
gpointer
data )
{
gtk_main_quit ();
return FALSE;
}
int main( int
argc,
char *argv[] )
{
GtkWidget *window = NULL;
GtkWidget *box1;
GtkWidget *box2;
GtkWidget *button;
GtkWidget *separator;
GSList *group;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (close_application),
NULL);
gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
41

Page 50
Chapter 6. The Button Widget
gtk_container_set_border_width (GTK_CONTAINER (window), 0);
box1 = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), box1);
gtk_widget_show (box1);
box2 = gtk_vbox_new (FALSE, 10);
gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
gtk_widget_show (box2);
button = gtk_radio_button_new_with_label (NULL, "button1");
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
button = gtk_radio_button_new_with_label (group, "button2");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
button = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (button),
"button3");
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
separator = gtk_hseparator_new ();
gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
gtk_widget_show (separator);
box2 = gtk_vbox_new (FALSE, 10);
gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
gtk_widget_show (box2);
button = gtk_button_new_with_label ("close");
g_signal_connect_swapped (G_OBJECT (button), "clicked",
G_CALLBACK (close_application),
window);
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_widget_show (window);
gtk_main ();
return 0;
}
42

Page 51
Chapter 7. Adjustments
GTK has various widgets that can be visually adjusted by the user using the mouse or the keyboard, such
as the range widgets, described in the Range Widgets section. There are also a few widgets that display
some adjustable portion of a larger area of data, such as the text widget and the viewport widget.
Obviously, an application needs to be able to react to changes the user makes in range widgets. One way
to do this would be to have each widget emit its own type of signal when its adjustment changes, and
either pass the new value to the signal handler, or require it to look inside the widget’s data structure in
order to ascertain the value. But you may also want to connect the adjustments of several widgets
together, so that adjusting one adjusts the others. The most obvious example of this is connecting a
scrollbar to a panning viewport or a scrolling text area. If each widget has its own way of setting or
getting the adjustment value, then the programmer may have to write their own signal handlers to
translate between the output of one widget’s signal and the "input" of another’s adjustment setting
function.
GTK solves this problem using the Adjustment object, which is not a widget but a way for widgets to
store and pass adjustment information in an abstract and flexible form. The most obvious use of
Adjustment is to store the configuration parameters and values of range widgets, such as scrollbars and
scale controls. However, since Adjustments are derived from Object, they have some special powers
beyond those of normal data structures. Most importantly, they can emit signals, just like widgets, and
these signals can be used not only to allow your program to react to user input on adjustable widgets, but
also to propagate adjustment values transparently between adjustable widgets.
You will see how adjustments fit in when you see the other widgets that incorporate them: Progress Bars,
Viewports, Scrolled Windows, and others.
7.1. Creating an Adjustment
Many of the widgets which use adjustment objects do so automatically, but some cases will be shown in
later examples where you may need to create one yourself. You create an adjustment using:
GtkObject *gtk_adjustment_new( gdouble value,
gdouble lower,
gdouble upper,
gdouble step_increment,
gdouble page_increment,
gdouble page_size );
The
value
argument is the initial value you want to give to the adjustment, usually corresponding to the
topmost or leftmost position of an adjustable widget. The
lower
argument specifies the lowest value
which the adjustment can hold. The
step_increment
argument specifies the "smaller" of the two
increments by which the user can change the value, while the
page_increment
is the "larger" one. The
43

Page 52
Chapter 7. Adjustments
page_size
argument usually corresponds somehow to the visible area of a panning widget. The
upper
argument is used to represent the bottom most or right most coordinate in a panning widget’s child.
Therefore it is not always the largest number that
value
can take, since the
page_size
of such widgets
is usually non-zero.
7.2. Using Adjustments the Easy Way
The adjustable widgets can be roughly divided into those which use and require specific units for these
values and those which treat them as arbitrary numbers. The group which treats the values as arbitrary
numbers includes the range widgets (scrollbars and scales, the progress bar widget, and the spin button
widget). These widgets are all the widgets which are typically "adjusted" directly by the user with the
mouse or keyboard. They will treat the
lower
and
upper
values of an adjustment as a range within
which the user can manipulate the adjustment’s
value
. By default, they will only modify the
value
of
an adjustment.
The other group includes the text widget, the viewport widget, the compound list widget, and the scrolled
window widget. All of these widgets use pixel values for their adjustments. These are also all widgets
which are typically "adjusted" indirectly using scrollbars. While all widgets which use adjustments can
either create their own adjustments or use ones you supply, you’ll generally want to let this particular
category of widgets create its own adjustments. Usually, they will eventually override all the values
except the
value
itself in whatever adjustments you give them, but the results are, in general, undefined
(meaning, you’ll have to read the source code to find out, and it may be different from widget to widget).
Now, you’re probably thinking, since text widgets and viewports insist on setting everything except the
value
of their adjustments, while scrollbars will only touch the adjustment’s
value
, if you share an
adjustment object between a scrollbar and a text widget, manipulating the scrollbar will automagically
adjust the viewport widget? Of course it will! Just like this:
/* creates its own adjustments */
viewport = gtk_viewport_new (NULL, NULL);
/* uses the newly-created adjustment for the scrollbar as well */
vscrollbar = gtk_vscrollbar_new (gtk_viewport_get_vadjustment (viewport));
7.3. Adjustment Internals
Ok, you say, that’s nice, but what if I want to create my own handlers to respond when the user adjusts a
range widget or a spin button, and how do I get at the value of the adjustment in these handlers? To
answer these questions and more, let’s start by taking a look at
struct _GtkAdjustment
itself:
struct _GtkAdjustment
{
GtkObject parent_instance;
gdouble lower;
44

Page 53
Chapter 7. Adjustments
gdouble upper;
gdouble value;
gdouble step_increment;
gdouble page_increment;
gdouble page_size;
};
If you don’t like to poke directly at struct internals like a real C programmer, you can use the following
accessor to inspect the
value
of an adjustment:
gdouble gtk_adjustment_get_value( GtkAdjustment *adjustment);
Since, when you set the
value
of an Adjustment, you generally want the change to be reflected by every
widget that uses this adjustment, GTK provides this convenience function to do this:
void gtk_adjustment_set_value( GtkAdjustment *adjustment,
gdouble
value );
As mentioned earlier, Adjustment is a subclass of Object just like all the various widgets, and thus it is
able to emit signals. This is, of course, why updates happen automagically when you share an adjustment
object between a scrollbar and another adjustable widget; all adjustable widgets connect signal handlers
to their adjustment’s
value_changed
signal, as can your program. Here’s the definition of this signal in
struct _GtkAdjustmentClass
:
void (* value_changed) (GtkAdjustment *adjustment);
The various widgets that use the Adjustment object will emit this signal on an adjustment whenever they
change its value. This happens both when user input causes the slider to move on a range widget, as well
as when the program explicitly changes the value with gtk_adjustment_set_value(). So, for example, if
you have a scale widget, and you want to change the rotation of a picture whenever its value changes,
you would create a callback like this:
void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
{
set_picture_rotation (picture, gtk_adjustment_get_value (adj));
...
and connect it to the scale widget’s adjustment like this:
g_signal_connect (G_OBJECT (adj), "value_changed",
G_CALLBACK (cb_rotate_picture), picture);
What about when a widget reconfigures the
upper
or
lower
fields of its adjustment, such as when a user
adds more text to a text widget? In this case, it emits the
changed
signal, which looks like this:
void (* changed) (GtkAdjustment *adjustment);
45

Page 54
Chapter 7. Adjustments
Range widgets typically connect a handler to this signal, which changes their appearance to reflect the
change - for example, the size of the slider in a scrollbar will grow or shrink in inverse proportion to the
difference between the
lower
and
upper
values of its adjustment.
You probably won’t ever need to attach a handler to this signal, unless you’re writing a new type of range
widget. However, if you change any of the values in a Adjustment directly, you should emit this signal on
it to reconfigure whatever widgets are using it, like this:
g_signal_emit_by_name (G_OBJECT (adjustment), "changed");
Now go forth and adjust!
46

Page 55
Chapter 8. Range Widgets
The category of range widgets includes the ubiquitous scrollbar widget and the less common scale
widget. Though these two types of widgets are generally used for different purposes, they are quite
similar in function and implementation. All range widgets share a set of common graphic elements, each
of which has its own X window and receives events. They all contain a "trough" and a "slider" (what is
sometimes called a "thumbwheel" in other GUI environments). Dragging the slider with the pointer
moves it back and forth within the trough, while clicking in the trough advances the slider towards the
location of the click, either completely, or by a designated amount, depending on which mouse button is
used.
As mentioned in Adjustments above, all range widgets are associated with an adjustment object, from
which they calculate the length of the slider and its position within the trough. When the user
manipulates the slider, the range widget will change the value of the adjustment.
8.1. Scrollbar Widgets
These are your standard, run-of-the-mill scrollbars. These should be used only for scrolling some other
widget, such as a list, a text box, or a viewport (and it’s generally easier to use the scrolled window
widget in most cases). For other purposes, you should use scale widgets, as they are friendlier and more
featureful.
There are separate types for horizontal and vertical scrollbars. There really isn’t much to say about these.
You create them with the following functions:
GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );
GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );
and that’s about it (if you don’t believe me, look in the header files!). The
adjustment
argument can
either be a pointer to an existing Adjustment, or NULL, in which case one will be created for you.
Specifying NULL might actually be useful in this case, if you wish to pass the newly-created adjustment
to the constructor function of some other widget which will configure it for you, such as a text widget.
8.2. Scale Widgets
Scale widgets are used to allow the user to visually select and manipulate a value within a specific range.
You might want to use a scale widget, for example, to adjust the magnification level on a zoomed
preview of a picture, or to control the brightness of a color, or to specify the number of minutes of
inactivity before a screensaver takes over the screen.
47

Page 56
Chapter 8. Range Widgets
8.2.1. Creating a Scale Widget
As with scrollbars, there are separate widget types for horizontal and vertical scale widgets. (Most
programmers seem to favour horizontal scale widgets.) Since they work essentially the same way, there’s
no need to treat them separately here. The following functions create vertical and horizontal scale
widgets, respectively:
GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );
GtkWidget *gtk_vscale_new_with_range( gdouble min,
gdouble max,
gdouble step );
GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );
GtkWidget *gtk_hscale_new_with_range( gdouble min,
gdouble max,
gdouble step );
The
adjustment
argument can either be an adjustment which has already been created with
gtk_adjustment_new(), or NULL, in which case, an anonymous Adjustment is created with all of its
values set to
0.0
(which isn’t very useful in this case). In order to avoid confusing yourself, you
probably want to create your adjustment with a
page_size
of
0.0
so that its
upper
value actually
corresponds to the highest value the user can select. The _new_with_range() variants take care of
creating a suitable adjustment. (If you’re already thoroughly confused, read the section on Adjustments
again for an explanation of what exactly adjustments do and how to create and manipulate them.)
8.2.2. Functions and Signals (well, functions, at least)
Scale widgets can display their current value as a number beside the trough. The default behaviour is to
show the value, but you can change this with this function:
void gtk_scale_set_draw_value( GtkScale *scale,
gboolean draw_value );
As you might have guessed,
draw_value
is either
TRUE
or
FALSE
, with predictable consequences for
either one.
The value displayed by a scale widget is rounded to one decimal point by default, as is the
value
field in
its Adjustment. You can change this with:
void gtk_scale_set_digits( GtkScale *scale,
gint
digits );
where
digits
is the number of decimal places you want. You can set
digits
to anything you like, but
no more than 13 decimal places will actually be drawn on screen.
48

Page 57
Chapter 8. Range Widgets
Finally, the value can be drawn in different positions relative to the trough:
void gtk_scale_set_value_pos( GtkScale
*scale,
GtkPositionType pos );
The argument
pos
is of type
GtkPositionType
, which can take one of the following values:
GTK_POS_LEFT
GTK_POS_RIGHT
GTK_POS_TOP
GTK_POS_BOTTOM
If you position the value on the "side" of the trough (e.g., on the top or bottom of a horizontal scale
widget), then it will follow the slider up and down the trough.
All the preceding functions are defined in
<gtk/gtkscale.h>
. The header files for all GTK widgets
are automatically included when you include
<gtk/gtk.h>
. But you should look over the header files
of all widgets that interest you, in order to learn more about their functions and features.
8.3. Common Range Functions
The Range widget class is fairly complicated internally, but, like all the "base class" widgets, most of its
complexity is only interesting if you want to hack on it. Also, almost all of the functions and signals it
defines are only really used in writing derived widgets. There are, however, a few useful functions that
are defined in
<gtk/gtkrange.h>
and will work on all range widgets.
8.3.1. Setting the Update Policy
The "update policy" of a range widget defines at what points during user interaction it will change the
value
field of its Adjustment and emit the "value_changed" signal on this Adjustment. The update
policies, defined in
<gtk/gtkenums.h>
as type
enum GtkUpdateType
, are:
GTK_UPDATE_CONTINUOUS
This is the default. The "value_changed" signal is emitted continuously, i.e., whenever the slider is
moved by even the tiniest amount.
GTK_UPDATE_DISCONTINUOUS
The "value_changed" signal is only emitted once the slider has stopped moving and the user has
released the mouse button.
GTK_UPDATE_DELAYED
The "value_changed" signal is emitted when the user releases the mouse button, or if the slider
stops moving for a short period of time.
49

Page 58
Chapter 8. Range Widgets
The update policy of a range widget can be set by casting it using the
GTK_RANGE(widget)
macro and
passing it to this function:
void gtk_range_set_update_policy( GtkRange
*range,
GtkUpdateType policy);
8.3.2. Getting and Setting Adjustments
Getting and setting the adjustment for a range widget "on the fly" is done, predictably, with:
GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
void gtk_range_set_adjustment( GtkRange
*range,
GtkAdjustment *adjustment );
gtk_range_get_adjustment()
returns a pointer to the adjustment to which
range
is connected.
gtk_range_set_adjustment()
does absolutely nothing if you pass it the adjustment that
range
is
already using, regardless of whether you changed any of its fields or not. If you pass it a new
Adjustment, it will unreference the old one if it exists (possibly destroying it), connect the appropriate
signals to the new one, and call the private function
gtk_range_adjustment_changed()
, which will
(or at least, is supposed to...) recalculate the size and/or position of the slider and redraw if necessary. As
mentioned in the section on adjustments, if you wish to reuse the same Adjustment, when you modify its
values directly, you should emit the "changed" signal on it, like this:
g_signal_emit_by_name (G_OBJECT (adjustment), "changed");
8.4. Key and Mouse bindings
All of the GTK range widgets react to mouse clicks in more or less the same way. Clicking button-1 in
the trough will cause its adjustment’s
page_increment
to be added or subtracted from its
value
, and
the slider to be moved accordingly. Clicking mouse button-2 in the trough will jump the slider to the
point at which the button was clicked. Clicking button-3 in the trough of a range or any button on a
scrollbar’s arrows will cause its adjustment’s value to change by
step_increment
at a time.
Scrollbars are not focusable, thus have no key bindings. The key bindings for the other range widgets
(which are, of course, only active when the widget has focus) are do not differentiate between horizontal
and vertical range widgets.
All range widgets can be operated with the left, right, up and down arrow keys, as well as with the
Page
Up
and
Page Down
keys. The arrows move the slider up and down by
step_increment
, while
Page
Up
and
Page Down
move it by
page_increment
.
50

Page 59
Chapter 8. Range Widgets
The user can also move the slider all the way to one end or the other of the trough using the keyboard.
This is done with the
Home
and
End
keys.
8.5. Example
This example is a somewhat modified version of the "range controls" test from
testgtk.c
. It basically
puts up a window with three range widgets all connected to the same adjustment, and a couple of
controls for adjusting some of the parameters mentioned above and in the section on adjustments, so you
can see how they affect the way these widgets work for the user.
#include <gtk/gtk.h>
GtkWidget *hscale, *vscale;
void cb_pos_menu_select( GtkWidget
*item,
GtkPositionType pos )
{
/* Set the value position on both scale widgets */
gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
}
void cb_update_menu_select( GtkWidget
*item,
GtkUpdateType policy )
{
/* Set the update policy for both scale widgets */
gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
}
void cb_digits_scale( GtkAdjustment *adj )
{
/* Set the number of decimal places to which adj->value is rounded */
gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
}
void cb_page_size( GtkAdjustment *get,
GtkAdjustment *set )
{
/* Set the page size and page increment size of the sample
* adjustment to the value specified by the "Page Size" scale */
set->page_size = get->value;
set->page_increment = get->value;
/* This sets the adjustment and makes it emit the "changed" signal to
reconfigure all the widgets that are attached to this signal. */
gtk_adjustment_set_value (set, CLAMP (set->value,
set->lower,
51

Page 60
Chapter 8. Range Widgets
(set->upper - set->page_size)));
}
void cb_draw_value( GtkToggleButton *button )
{
/* Turn the value display on the scale widgets off or on depending
* on the state of the checkbutton */
gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active);
gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active);
}
/* Convenience functions */
GtkWidget *make_menu_item (gchar
*name,
GCallback callback,
gpointer
data)
{
GtkWidget *item;
item = gtk_menu_item_new_with_label (name);
g_signal_connect (G_OBJECT (item), "activate",
callback, data);
gtk_widget_show (item);
return item;
}
void scale_set_default_values( GtkScale *scale )
{
gtk_range_set_update_policy (GTK_RANGE (scale),
GTK_UPDATE_CONTINUOUS);
gtk_scale_set_digits (scale, 1);
gtk_scale_set_value_pos (scale, GTK_POS_TOP);
gtk_scale_set_draw_value (scale, TRUE);
}
/* makes the sample window */
void create_range_controls( void )
{
GtkWidget *window;
GtkWidget *box1, *box2, *box3;
GtkWidget *button;
GtkWidget *scrollbar;
GtkWidget *separator;
GtkWidget *opt, *menu, *item;
GtkWidget *label;
GtkWidget *scale;
GtkObject *adj1, *adj2;
/* Standard window-creating stuff */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT (window), "destroy",
52

Page 61
Chapter 8. Range Widgets
G_CALLBACK (gtk_main_quit),
NULL);
gtk_window_set_title (GTK_WINDOW (window), "range controls");
box1 = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), box1);
gtk_widget_show (box1);
box2 = gtk_hbox_new (FALSE, 10);
gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
gtk_widget_show (box2);
/* value, lower, upper, step_increment, page_increment, page_size */
/* Note that the page_size value only makes a difference for
* scrollbar widgets, and the highest value you’ll get is actually
* (upper - page_size). */
adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
scale_set_default_values (GTK_SCALE (vscale));
gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0);
gtk_widget_show (vscale);
box3 = gtk_vbox_new (FALSE, 10);
gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0);
gtk_widget_show (box3);
/* Reuse the same adjustment */
hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
gtk_widget_set_size_request (GTK_WIDGET (hscale), 200, -1);
scale_set_default_values (GTK_SCALE (hscale));
gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0);
gtk_widget_show (hscale);
/* Reuse the same adjustment again */
scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
/* Notice how this causes the scales to always be updated
* continuously when the scrollbar is moved */
gtk_range_set_update_policy (GTK_RANGE (scrollbar),
GTK_UPDATE_CONTINUOUS);
gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0);
gtk_widget_show (scrollbar);
box2 = gtk_hbox_new (FALSE, 10);
gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
gtk_widget_show (box2);
/* A checkbutton to control whether the value is displayed or not */
button = gtk_check_button_new_with_label("Display value on scale widgets");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
g_signal_connect (G_OBJECT (button), "toggled",
53

Page 62
Chapter 8. Range Widgets
G_CALLBACK (cb_draw_value), NULL);
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
box2 = gtk_hbox_new (FALSE, 10);
gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
/* An option menu to change the position of the value */
label = gtk_label_new ("Scale Value Position:");
gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
gtk_widget_show (label);
opt = gtk_option_menu_new ();
menu = gtk_menu_new ();
item = make_menu_item ("Top",
G_CALLBACK (cb_pos_menu_select),
GINT_TO_POINTER (GTK_POS_TOP));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
item = make_menu_item ("Bottom", G_CALLBACK (cb_pos_menu_select),
GINT_TO_POINTER (GTK_POS_BOTTOM));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
item = make_menu_item ("Left", G_CALLBACK (cb_pos_menu_select),
GINT_TO_POINTER (GTK_POS_LEFT));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
item = make_menu_item ("Right", G_CALLBACK (cb_pos_menu_select),
GINT_TO_POINTER (GTK_POS_RIGHT));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
gtk_widget_show (opt);
gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
gtk_widget_show (box2);
box2 = gtk_hbox_new (FALSE, 10);
gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
/* Yet another option menu, this time for the update policy of the
* scale widgets */
label = gtk_label_new ("Scale Update Policy:");
gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
gtk_widget_show (label);
opt = gtk_option_menu_new ();
menu = gtk_menu_new ();
item = make_menu_item ("Continuous",
G_CALLBACK (cb_update_menu_select),
54

Page 63
Chapter 8. Range Widgets
GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
item = make_menu_item ("Discontinuous",
G_CALLBACK (cb_update_menu_select),
GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
item = make_menu_item ("Delayed",
G_CALLBACK (cb_update_menu_select),
GINT_TO_POINTER (GTK_UPDATE_DELAYED));
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
gtk_widget_show (opt);
gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
gtk_widget_show (box2);
box2 = gtk_hbox_new (FALSE, 10);
gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
/* An HScale widget for adjusting the number of digits on the
* sample scales. */
label = gtk_label_new ("Scale Digits:");
gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
gtk_widget_show (label);
adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
g_signal_connect (G_OBJECT (adj2), "value_changed",
G_CALLBACK (cb_digits_scale), NULL);
scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
gtk_scale_set_digits (GTK_SCALE (scale), 0);
gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
gtk_widget_show (scale);
gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
gtk_widget_show (box2);
box2 = gtk_hbox_new (FALSE, 10);
gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
/* And, one last HScale widget for adjusting the page size of the
* scrollbar. */
label = gtk_label_new ("Scrollbar Page Size:");
gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
gtk_widget_show (label);
adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
g_signal_connect (G_OBJECT (adj2), "value_changed",
G_CALLBACK (cb_page_size), adj1);
scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
55

Page 64
Chapter 8. Range Widgets
gtk_scale_set_digits (GTK_SCALE (scale), 0);
gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
gtk_widget_show (scale);
gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
gtk_widget_show (box2);
separator = gtk_hseparator_new ();
gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
gtk_widget_show (separator);
box2 = gtk_vbox_new (FALSE, 10);
gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
gtk_widget_show (box2);
button = gtk_button_new_with_label ("Quit");
g_signal_connect_swapped (G_OBJECT (button), "clicked",
G_CALLBACK (gtk_main_quit),
NULL);
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_widget_show (window);
}
int main( int
argc,
char *argv[] )
{
gtk_init (&argc, &argv);
create_range_controls ();
gtk_main ();
return 0;
}
You will notice that the program does not call g_signal_connect() for the "delete_event", but only for the
"destroy" signal. This will still perform the desired function, because an unhandled "delete_event" will
result in a "destroy" signal being given to the window.
56

Page 65
Chapter 9. Miscellaneous Widgets
9.1. Labels
Labels are used a lot in GTK, and are relatively simple. Labels emit no signals as they do not have an
associated X window. If you need to catch signals, or do clipping, place it inside a EventBox widget or a
Button widget.
To create a new label, use:
GtkWidget *gtk_label_new( const char *str );
GtkWidget *gtk_label_new_with_mnemonic( const char *str );
The sole argument is the string you wish the label to display.
To change the label’s text after creation, use the function:
void gtk_label_set_text( GtkLabel
*label,
const char *str );
The first argument is the label you created previously (cast using the
GTK_LABEL()
macro), and the
second is the new string.
The space needed for the new string will be automatically adjusted if needed. You can produce multi-line
labels by putting line breaks in the label string.
To retrieve the current string, use:
const gchar* gtk_label_get_text( GtkLabel *label );
Do not free the returned string, as it is used internally by GTK.
The label text can be justified using:
void gtk_label_set_justify( GtkLabel
*label,
GtkJustification jtype );
Values for
jtype
are:
GTK_JUSTIFY_LEFT
GTK_JUSTIFY_RIGHT
GTK_JUSTIFY_CENTER (the default)
57

Page 66
Chapter 9. Miscellaneous Widgets
GTK_JUSTIFY_FILL
The label widget is also capable of line wrapping the text automatically. This can be activated using:
void gtk_label_set_line_wrap (GtkLabel *label,
gboolean wrap);
The
wrap
argument takes a TRUE or FALSE value.
If you want your label underlined, then you can set a pattern on the label:
void
gtk_label_set_pattern
(GtkLabel
*label,
const gchar
*pattern);
The pattern argument indicates how the underlining should look. It consists of a string of underscore and
space characters. An underscore indicates that the corresponding character in the label should be
underlined. For example, the string
"__ __"
would underline the first two characters and eight and ninth
characters.
Note: If you simply want to have an underlined accelerator ("mnemonic") in your label, you should
use gtk_label_new_with_mnemonic() or gtk_label_set_text_with_mnemonic(), not
gtk_label_set_pattern().
Below is a short example to illustrate these functions. This example makes use of the Frame widget to
better demonstrate the label styles. You can ignore this for now as the Frame widget is explained later on.
In GTK+ 2.0, label texts can contain markup for font and other text attribute changes, and labels may be
selectable (for copy-and-paste). These advanced features won’t be explained here.
#include <gtk/gtk.h>
int main( int
argc,
char *argv[] )
{
static GtkWidget *window = NULL;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *label;
/* Initialise GTK */
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
58

Page 67
Chapter 9. Miscellaneous Widgets
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit),
NULL);
gtk_window_set_title (GTK_WINDOW (window), "Label");
vbox = gtk_vbox_new (FALSE, 5);
hbox = gtk_hbox_new (FALSE, 5);
gtk_container_add (GTK_CONTAINER (window), hbox);
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (window), 5);
frame = gtk_frame_new ("Normal Label");
label = gtk_label_new ("This is a Normal label");
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
frame = gtk_frame_new ("Multi-line Label");
label = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
"Third line");
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
frame = gtk_frame_new ("Left Justified Label");
label = gtk_label_new ("This is a Left-Justified\n" \
"Multi-line label.\nThird
line");
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
frame = gtk_frame_new ("Right Justified Label");
label = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
"Fourth line, (j/k)");
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
vbox = gtk_vbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
frame = gtk_frame_new ("Line wrapped label");
label = gtk_label_new ("This is an example of a line-wrapped label. It " \
"should not be taking up the entire
" /* big space to test spacing */\
"width allocated to it, but automatically " \
"wraps the words to fit. " \
"The time has come, for all good men, to come to " \
"the aid of their party. " \
"The sixth sheik’s six sheep’s sick.\n" \
"
It supports multiple paragraphs correctly, " \
"and correctly
adds "\
"many
extra spaces. ");
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
59

Page 68
Chapter 9. Miscellaneous Widgets
frame = gtk_frame_new ("Filled, wrapped label");
label = gtk_label_new ("This is an example of a line-wrapped, filled label. " \
"It should be taking "\
"up the entire
width allocated to it. " \
"Here is a sentence to prove "\
"my point. Here is another sentence. "\
"Here comes the sun, do de do de do.\n"\
"
This is a new paragraph.\n"\
"
This is another newer, longer, better " \
"paragraph. It is coming to an end, "\
"unfortunately.");
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
frame = gtk_frame_new ("Underlined label");
label = gtk_label_new ("This label is underlined!\n"
"This one is underlined in quite a funky fashion");
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
gtk_label_set_pattern (GTK_LABEL (label),
"_________________________ _ _________ _ ______
__ _______ ___");
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
9.2. Arrows
The Arrow widget draws an arrowhead, facing in a number of possible directions and having a number of
possible styles. It can be very useful when placed on a button in many applications. Like the Label
widget, it emits no signals.
There are only two functions for manipulating an Arrow widget:
GtkWidget *gtk_arrow_new( GtkArrowType
arrow_type,
GtkShadowType shadow_type );
void gtk_arrow_set( GtkArrow
*arrow,
GtkArrowType
arrow_type,
GtkShadowType shadow_type );
60

Page 69
Chapter 9. Miscellaneous Widgets
The first creates a new arrow widget with the indicated type and appearance. The second allows these
values to be altered retrospectively. The
arrow_type
argument may take one of the following values:
GTK_ARROW_UP
GTK_ARROW_DOWN
GTK_ARROW_LEFT
GTK_ARROW_RIGHT
These values obviously indicate the direction in which the arrow will point. The
shadow_type
argument may take one of these values:
GTK_SHADOW_IN
GTK_SHADOW_OUT (the default)
GTK_SHADOW_ETCHED_IN
GTK_SHADOW_ETCHED_OUT
Here’s a brief example to illustrate their use.
#include <gtk/gtk.h>
/* Create an Arrow widget with the specified parameters
* and pack it into a button */
GtkWidget *create_arrow_button( GtkArrowType arrow_type,
GtkShadowType shadow_type )
{
GtkWidget *button;
GtkWidget *arrow;
button = gtk_button_new ();
arrow = gtk_arrow_new (arrow_type, shadow_type);
gtk_container_add (GTK_CONTAINER (button), arrow);
gtk_widget_show (button);
gtk_widget_show (arrow);
return button;
}
int main( int
argc,
char *argv[] )
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *button;
GtkWidget *box;
/* Initialize the toolkit */
gtk_init (&argc, &argv);
61

Page 70
Chapter 9. Miscellaneous Widgets
/* Create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Arrow Buttons");
/* It’s a good idea to do this for all windows. */
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Create a box to hold the arrows/buttons */
box = gtk_hbox_new (FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (box), 2);
gtk_container_add (GTK_CONTAINER (window), box);
/* Pack and show all our widgets */
gtk_widget_show (box);
button = create_arrow_button (GTK_ARROW_UP, GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
button = create_arrow_button (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
button = create_arrow_button (GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
button = create_arrow_button (GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
gtk_widget_show (window);
/* Rest in gtk_main and wait for the fun to begin! */
gtk_main ();
return 0;
}
9.3. The Tooltips Object
These are the little text strings that pop up when you leave your pointer over a button or other widget for
a few seconds. They are easy to use, so I will just explain them without giving an example. If you want to
see some code, take a look at the
testgtk.c
program distributed with GTK.
Widgets that do not receive events (widgets that do not have their own window) will not work with
tooltips.
62

Page 71
Chapter 9. Miscellaneous Widgets
The first call you will use creates a new tooltip. You only need to do this once for a set of tooltips as the
GtkTooltips
object this function returns can be used to create multiple tooltips.
GtkTooltips *gtk_tooltips_new( void );
Once you have created a new tooltip, and the widget you wish to use it on, simply use this call to set it:
void gtk_tooltips_set_tip( GtkTooltips *tooltips,
GtkWidget
*widget,
const gchar *tip_text,
const gchar *tip_private );
The first argument is the tooltip you’ve already created, followed by the widget you wish to have this
tooltip pop up for, and the text you wish it to say. The last argument is a text string that can be used as an
identifier when using GtkTipsQuery to implement context sensitive help. For now, you can set it to
NULL.
Here’s a short example:
GtkTooltips *tooltips;
GtkWidget *button;
.
.
.
tooltips = gtk_tooltips_new ();
button = gtk_button_new_with_label ("button 1");
.
.
.
gtk_tooltips_set_tip (tooltips, button, "This is button 1", NULL);
There are other calls that can be used with tooltips. I will just list them with a brief description of what
they do.
void gtk_tooltips_enable( GtkTooltips *tooltips );
Enable a disabled set of tooltips.
void gtk_tooltips_disable( GtkTooltips *tooltips );
Disable an enabled set of tooltips.
And that’s all the functions associated with tooltips. More than you’ll ever want to know :-)
63

Page 72
Chapter 9. Miscellaneous Widgets
9.4. Progress Bars
Progress bars are used to show the status of an operation. They are pretty easy to use, as you will see
with the code below. But first lets start out with the calls to create a new progress bar.
GtkWidget *gtk_progress_bar_new( void );
Now that the progress bar has been created we can use it.
void gtk_progress_bar_set_fraction ( GtkProgressBar *pbar,
gdouble
fraction );
The first argument is the progress bar you wish to operate on, and the second argument is the amount
"completed", meaning the amount the progress bar has been filled from 0-100%. This is passed to the
function as a real number ranging from 0 to 1.
GTK v1.2 has added new functionality to the progress bar that enables it to display its value in different
ways, and to inform the user of its current value and its range.
A progress bar may be set to one of a number of orientations using the function
void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
GtkProgressBarOrientation orientation );
The
orientation
argument may take one of the following values to indicate the direction in which the
progress bar moves:
GTK_PROGRESS_LEFT_TO_RIGHT
GTK_PROGRESS_RIGHT_TO_LEFT
GTK_PROGRESS_BOTTOM_TO_TOP
GTK_PROGRESS_TOP_TO_BOTTOM
As well as indicating the amount of progress that has occured, the progress bar may be set to just indicate
that there is some activity. This can be useful in situations where progress cannot be measured against a
value range. To following function indicates that some progress has been made.
void gtk_progress_bar_pulse ( GtkProgressBar *progress );
The step size of the activity indicator is set using the following function.
void gtk_progress_bar_set_pulse_step( GtkProgressBar *pbar,
gdouble
fraction );
When not in activity mode, the progress bar can also display a configurable text string within its trough,
using the following function.
64

Page 73
Chapter 9. Miscellaneous Widgets
void gtk_progress_bar_set_text( GtkProgressBar *progress,
const gchar
*text );
Note: Note that gtk_progress_set_text() doesn’t support the printf()-like formatting of the GTK+ 1.2
Progressbar.
You can turn off the display of the string by calling gtk_progess_bar_set_text() again with NULL as
second argument.
The current text setting of a progressbar can be retrieved with the following function. Do not free the
returned string.
const gchar *gtk_progress_bar_get_text( GtkProgressBar *pbar );
Progress Bars are usually used with timeouts or other such functions (see section on Timeouts, I/O and
Idle Functions) to give the illusion of multitasking. All will employ the gtk_progress_bar_set_fraction()
or gtk_progress_bar_pulse() functions in the same manner.
Here is an example of the progress bar, updated using timeouts. This code also shows you how to reset
the Progress Bar.
#include <gtk/gtk.h>
typedef struct _ProgressData {
GtkWidget *window;
GtkWidget *pbar;
int timer;
gboolean activity_mode;
} ProgressData;
/* Update the value of the progress bar so that we get
* some movement */
gint progress_timeout( gpointer data )
{
ProgressData *pdata = (ProgressData *)data;
gdouble new_val;
if (pdata->activity_mode)
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata->pbar));
else
{
/* Calculate the value of the progress bar using the
* value range set in the adjustment object */
new_val = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (pdata->pbar)) + 0.01;
65

Page 74
Chapter 9. Miscellaneous Widgets
if (new_val > 1.0)
new_val = 0.0;
/* Set the new value */
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata->pbar), new_val);
}
/* As this is a timeout function, return TRUE so that it
* continues to get called */
return TRUE;
}
/* Callback that toggles the text display within the progress bar trough */
void toggle_show_text( GtkWidget
*widget,
ProgressData *pdata )
{
const gchar *text;
text = gtk_progress_bar_get_text (GTK_PROGRESS_BAR (pdata->pbar));
if (text && *text)
gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata->pbar), "");
else
gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata->pbar), "some text");
}
/* Callback that toggles the activity mode of the progress bar */
void toggle_activity_mode( GtkWidget
*widget,
ProgressData *pdata )
{
pdata->activity_mode = !pdata->activity_mode;
if (pdata->activity_mode)
gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata->pbar));
else
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata->pbar), 0.0);
}
/* Callback that toggles the orientation of the progress bar */
void toggle_orientation( GtkWidget
*widget,
ProgressData *pdata )
{
switch (gtk_progress_bar_get_orientation (GTK_PROGRESS_BAR (pdata->pbar))) {
case GTK_PROGRESS_LEFT_TO_RIGHT:
gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (pdata->pbar),
GTK_PROGRESS_RIGHT_TO_LEFT);
break;
case GTK_PROGRESS_RIGHT_TO_LEFT:
gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (pdata->pbar),
GTK_PROGRESS_LEFT_TO_RIGHT);
break;
default:
// do nothing
66

Page 75
Chapter 9. Miscellaneous Widgets
}
}
/* Clean up allocated memory and remove the timer */
void destroy_progress( GtkWidget
*widget,
ProgressData *pdata)
{
gtk_timeout_remove (pdata->timer);
pdata->timer = 0;
pdata->window = NULL;
g_free (pdata);
gtk_main_quit ();
}
int main( int
argc,
char *argv[])
{
ProgressData *pdata;
GtkWidget *align;
GtkWidget *separator;
GtkWidget *table;
GtkWidget *button;
GtkWidget *check;
GtkWidget *vbox;
gtk_init (&argc, &argv);
/* Allocate memory for the data that is passed to the callbacks */
pdata = g_malloc (sizeof (ProgressData));
pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_resizable (GTK_WINDOW (pdata->window), TRUE);
g_signal_connect (G_OBJECT (pdata->window), "destroy",
G_CALLBACK (destroy_progress),
pdata);
gtk_window_set_title (GTK_WINDOW (pdata->window), "GtkProgressBar");
gtk_container_set_border_width (GTK_CONTAINER (pdata->window), 0);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
gtk_widget_show (vbox);
/* Create a centering alignment object */
align = gtk_alignment_new (0.5, 0.5, 0, 0);
gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
gtk_widget_show (align);
/* Create the GtkProgressBar */
pdata->pbar = gtk_progress_bar_new ();
67

Page 76
Chapter 9. Miscellaneous Widgets
gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
gtk_widget_show (pdata->pbar);
/* Add a timer callback to update the value of the progress bar */
pdata->timer = gtk_timeout_add (100, progress_timeout, pdata);
separator = gtk_hseparator_new ();
gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
gtk_widget_show (separator);
/* rows, columns, homogeneous */
table = gtk_table_new (2, 2, FALSE);
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
gtk_widget_show (table);
/* Add a check button to select displaying of the trough text */
check = gtk_check_button_new_with_label ("Show text");
gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
5, 5);
g_signal_connect (G_OBJECT (check), "clicked",
G_CALLBACK (toggle_show_text),
pdata);
gtk_widget_show (check);
/* Add a check button to toggle activity mode */
check = gtk_check_button_new_with_label ("Activity mode");
gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
5, 5);
g_signal_connect (G_OBJECT (check), "clicked",
G_CALLBACK (toggle_activity_mode),
pdata);
gtk_widget_show (check);
/* Add a check button to toggle orientation */
check = gtk_check_button_new_with_label ("Right to Left");
gtk_table_attach (GTK_TABLE (table), check, 0, 1, 2, 3,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
5, 5);
g_signal_connect (G_OBJECT (check), "clicked",
G_CALLBACK (toggle_orientation),
pdata);
gtk_widget_show (check);
/* Add a button to exit the program */
button = gtk_button_new_with_label ("close");
g_signal_connect_swapped (G_OBJECT (button), "clicked",
G_CALLBACK (gtk_widget_destroy),
pdata->window);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
/* This makes it so the button is the default. */
68

Page 77
Chapter 9. Miscellaneous Widgets
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
/* This grabs this button to be the default button. Simply hitting
* the "Enter" key will cause this button to activate. */
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_widget_show (pdata->window);
gtk_main ();
return 0;
}
9.5. Dialogs
The Dialog widget is very simple, and is actually just a window with a few things pre-packed into it for
you. The structure for a Dialog is:
struct GtkDialog
{
GtkWindow window;
GtkWidget *vbox;
GtkWidget *action_area;
};
So you see, it simply creates a window, and then packs a vbox into the top, which contains a separator
and then an hbox called the "action_area".
The Dialog widget can be used for pop-up messages to the user, and other similar tasks. There are two
functions to create a new Dialog.
GtkWidget *gtk_dialog_new( void );
GtkWidget *gtk_dialog_new_with_buttons( const gchar
*title,
GtkWindow
*parent,
GtkDialogFlags flags,
const gchar
*first_button_text,
... );
The first function will create an empty dialog, and it is now up to you to use it. You could pack a button
in the action_area by doing something like this:
button = ...
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
button, TRUE, TRUE, 0);
69

Page 78
Chapter 9. Miscellaneous Widgets
gtk_widget_show (button);
And you could add to the vbox area by packing, for instance, a label in it, try something like this:
label = gtk_label_new ("Dialogs are groovy");
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
label, TRUE, TRUE, 0);
gtk_widget_show (label);
As an example in using the dialog box, you could put two buttons in the action_area, a Cancel button and
an Ok button, and a label in the vbox area, asking the user a question or giving an error etc. Then you
could attach a different signal to each of the buttons and perform the operation the user selects.
If the simple functionality provided by the default vertical and horizontal boxes in the two areas doesn’t
give you enough control for your application, then you can simply pack another layout widget into the
boxes provided. For example, you could pack a table into the vertical box.
The more complicated _new_with_buttons() variant allows to set one or more of the following flags.
GTK_DIALOG_MODAL
make the dialog modal.
GTK_DIALOG_DESTROY_WITH_PARENTS
ensures that the dialog window is destroyed together with the specified parent.
GTK_DIALOG_NO_SEPARATOR
omits the separator between the vbox and the action_area.
9.6. Rulers
Ruler widgets are used to indicate the location of the mouse pointer in a given window. A window can
have a vertical ruler spanning across the width and a horizontal ruler spanning down the height. A small
triangular indicator on the ruler shows the exact location of the pointer relative to the ruler.
A ruler must first be created. Horizontal and vertical rulers are created using
GtkWidget *gtk_hruler_new( void );
/* horizontal ruler */
GtkWidget *gtk_vruler_new( void );
/* vertical ruler
*/
Once a ruler is created, we can define the unit of measurement. Units of measure for rulers can
be
GTK_PIXELS
,
GTK_INCHES
or
GTK_CENTIMETERS
. This is set using
70

Page 79
Chapter 9. Miscellaneous Widgets
void gtk_ruler_set_metric( GtkRuler
*ruler,
GtkMetricType metric );
The default measure is
GTK_PIXELS
.
gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
Other important characteristics of a ruler are how to mark the units of scale and where the position
indicator is initially placed. These are set for a ruler using
void gtk_ruler_set_range( GtkRuler *ruler,
gdouble
lower,
gdouble
upper,
gdouble
position,
gdouble
max_size );
The lower and upper arguments define the extent of the ruler, and max_size is the largest possible number
that will be displayed. Position defines the initial position of the pointer indicator within the ruler.
A vertical ruler can span an 800 pixel wide window thus
gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
The markings displayed on the ruler will be from 0 to 800, with a number for every 100 pixels. If instead
we wanted the ruler to range from 7 to 16, we would code
gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
The indicator on the ruler is a small triangular mark that indicates the position of the pointer relative to
the ruler. If the ruler is used to follow the mouse pointer, the motion_notify_event signal should be
connected to the motion_notify_event method of the ruler. To follow all mouse movements within a
window area, we would use
#define EVENT_METHOD(i, x) GTK_WIDGET_GET_CLASS(i)->x
g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
G_CALLBACK (EVENT_METHOD (ruler, motion_notify_event)),
G_OBJECT (ruler));
The following example creates a drawing area with a horizontal ruler above it and a vertical ruler to the
left of it. The size of the drawing area is 600 pixels wide by 400 pixels high. The horizontal ruler spans
from 7 to 13 with a mark every 100 pixels, while the vertical ruler spans from 0 to 400 with a mark every
100 pixels. Placement of the drawing area and the rulers is done using a table.
#include <gtk/gtk.h>
71

Page 80
Chapter 9. Miscellaneous Widgets
#define EVENT_METHOD(i, x) GTK_WIDGET_GET_CLASS(i)->x
#define XSIZE 600
#define YSIZE 400
/* This routine gets control when the close button is clicked */
gint close_application( GtkWidget *widget,
GdkEvent *event,
gpointer
data )
{
gtk_main_quit ();
return FALSE;
}
/* The main routine */
int main( int
argc,
char *argv[] ) {
GtkWidget *window, *table, *area, *hrule, *vrule;
/* Initialize GTK and create the main window */
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (close_application), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Create a table for placing the ruler and the drawing area */
table = gtk_table_new (3, 2, FALSE);
gtk_container_add (GTK_CONTAINER (window), table);
area = gtk_drawing_area_new ();
gtk_widget_set_size_request (GTK_WIDGET (area), XSIZE, YSIZE);
gtk_table_attach (GTK_TABLE (table), area, 1, 2, 1, 2,
GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_set_events (area, GDK_POINTER_MOTION_MASK |
GDK_POINTER_MOTION_HINT_MASK);
/* The horizontal ruler goes on top. As the mouse moves across the
* drawing area, a motion_notify_event is passed to the
* appropriate event handler for the ruler. */
hrule = gtk_hruler_new ();
gtk_ruler_set_metric (GTK_RULER (hrule), GTK_PIXELS);
gtk_ruler_set_range (GTK_RULER (hrule), 7, 13, 0, 20);
g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
G_CALLBACK (EVENT_METHOD (hrule, motion_notify_event)),
hrule);
gtk_table_attach (GTK_TABLE (table), hrule, 1, 2, 0, 1,
GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0);
/* The vertical ruler goes on the left. As the mouse moves across
* the drawing area, a motion_notify_event is passed to the
72

Page 81
Chapter 9. Miscellaneous Widgets
* appropriate event handler for the ruler. */
vrule = gtk_vruler_new ();
gtk_ruler_set_metric (GTK_RULER (vrule), GTK_PIXELS);
gtk_ruler_set_range (GTK_RULER (vrule), 0, YSIZE, 10, YSIZE );
g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
G_CALLBACK (EVENT_METHOD (vrule, motion_notify_event)),
vrule);
gtk_table_attach (GTK_TABLE (table), vrule, 0, 1, 1, 2,
GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0);
/* Now show everything */
gtk_widget_show (area);
gtk_widget_show (hrule);
gtk_widget_show (vrule);
gtk_widget_show (table);
gtk_widget_show (window);
gtk_main ();
return 0;
}
9.7. Statusbars
Statusbars are simple widgets used to display a text message. They keep a stack of the messages pushed
onto them, so that popping the current message will re-display the previous text message.
In order to allow different parts of an application to use the same statusbar to display messages, the
statusbar widget issues Context Identifiers which are used to identify different "users". The message on
top of the stack is the one displayed, no matter what context it is in. Messages are stacked in
last-in-first-out order, not context identifier order.
A statusbar is created with a call to:
GtkWidget *gtk_statusbar_new( void );
A new Context Identifier is requested using a call to the following function with a short textual
description of the context:
guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
const gchar *context_description );
There are three functions that can operate on statusbars:
guint gtk_statusbar_push( GtkStatusbar *statusbar,
guint
context_id,
const gchar *text );
73

Page 82
Chapter 9. Miscellaneous Widgets
void gtk_statusbar_pop( GtkStatusbar *statusbar)
guint
context_id );
void gtk_statusbar_remove( GtkStatusbar *statusbar,
guint
context_id,
guint
message_id );
The first, gtk_statusbar_push(), is used to add a new message to the statusbar. It returns a Message
Identifier, which can be passed later to the function gtk_statusbar_remove to remove the message with
the given Message and Context Identifiers from the statusbar’s stack.
The function gtk_statusbar_pop() removes the message highest in the stack with the given Context
Identifier.
In addition to messages, statusbars may also display a resize grip, which can be dragged with the mouse
to resize the toplevel window containing the statusbar, similar to dragging the window frame. The
following functions control the display of the resize grip.
void
gtk_statusbar_set_has_resize_grip( GtkStatusbar *statusbar,
gboolean
setting );
gboolean gtk_statusbar_get_has_resize_grip( GtkStatusbar *statusbar );
The following example creates a statusbar and two buttons, one for pushing items onto the statusbar, and
one for popping the last item back off.
#include <stdlib.h>
#include <gtk/gtk.h>
#include <glib.h>
GtkWidget *status_bar;
void push_item( GtkWidget *widget,
gpointer
data )
{
static int count = 1;
char buff[20];
g_snprintf (buff, 20, "Item %d", count++);
gtk_statusbar_push (GTK_STATUSBAR (status_bar), GPOINTER_TO_INT (data), buff);
return;
}
void pop_item( GtkWidget *widget,
gpointer
data )
{
gtk_statusbar_pop (GTK_STATUSBAR (status_bar), GPOINTER_TO_INT (data));
74

Page 83
Chapter 9. Miscellaneous Widgets
return;
}
int main( int
argc,
char *argv[] )
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *button;
gint context_id;
gtk_init (&argc, &argv);
/* create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
gtk_window_set_title (GTK_WINDOW (window), "GTK Statusbar Example");
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (exit), NULL);
vbox = gtk_vbox_new (FALSE, 1);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show (vbox);
status_bar = gtk_statusbar_new ();
gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
gtk_widget_show (status_bar);
context_id = gtk_statusbar_get_context_id(
GTK_STATUSBAR (status_bar), "Statusbar example");
button = gtk_button_new_with_label ("push item");
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (push_item), GINT_TO_POINTER (context_id));
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 2);
gtk_widget_show (button);
button = gtk_button_new_with_label ("pop last item");
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (pop_item), GINT_TO_POINTER (context_id));
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 2);
gtk_widget_show (button);
/* always display the window as the last step so it all splashes on
* the screen at once. */
gtk_widget_show (window);
gtk_main ();
return 0;
}
75

Page 84
Chapter 9. Miscellaneous Widgets
9.8. Text Entries
The Entry widget allows text to be typed and displayed in a single line text box. The text may be set with
function calls that allow new text to replace, prepend or append the current contents of the Entry widget.
Create a new Entry widget with the following function.
GtkWidget *gtk_entry_new( void );
The next function alters the text which is currently within the Entry widget.
void gtk_entry_set_text( GtkEntry
*entry,
const gchar *text );
The function gtk_entry_set_text() sets the contents of the Entry widget, replacing the current contents.
Note that the class Entry implements the Editable interface (yes, gobject supports Java-like interfaces)
which contains some more functions for manipulating the contents.
The contents of the Entry can be retrieved by using a call to the following function. This is useful in the
callback functions described below.
const gchar *gtk_entry_get_text( GtkEntry *entry );
The value returned by this function is used internally, and must not be freed using either free() or
g_free().
If we don’t want the contents of the Entry to be changed by someone typing into it, we can change its
editable state.
void gtk_editable_set_editable( GtkEditable *entry,
gboolean
editable );
The function above allows us to toggle the editable state of the Entry widget by passing in a TRUE or
FALSE value for the
editable
argument.
If we are using the Entry where we don’t want the text entered to be visible, for example when a
password is being entered, we can use the following function, which also takes a boolean flag.
void gtk_entry_set_visibility( GtkEntry *entry,
gboolean visible );
A region of the text may be set as selected by using the following function. This would most often be
used after setting some default text in an Entry, making it easy for the user to remove it.
void gtk_editable_select_region( GtkEditable *entry,
76

Page 85
Chapter 9. Miscellaneous Widgets
gint
start,
gint
end );
If we want to catch when the user has entered text, we can connect to the
activate
or
changed
signal.
Activate is raised when the user hits the enter key within the Entry widget. Changed is raised when the
text changes at all, e.g., for every character entered or removed.
The following code is an example of using an Entry widget.
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
void enter_callback( GtkWidget *widget,
GtkWidget *entry )
{
const gchar *entry_text;
entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
printf("Entry contents: %s\n", entry_text);
}
void entry_toggle_editable( GtkWidget *checkbutton,
GtkWidget *entry )
{
gtk_editable_set_editable (GTK_EDITABLE (entry),
GTK_TOGGLE_BUTTON (checkbutton)->active);
}
void entry_toggle_visibility( GtkWidget *checkbutton,
GtkWidget *entry )
{
gtk_entry_set_visibility (GTK_ENTRY (entry),
GTK_TOGGLE_BUTTON (checkbutton)->active);
}
int main( int
argc,
char *argv[] )
{
GtkWidget *window;
GtkWidget *vbox, *hbox;
GtkWidget *entry;
GtkWidget *button;
GtkWidget *check;
gint tmp_pos;
gtk_init (&argc, &argv);
/* create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
77

Page 86
Chapter 9. Miscellaneous Widgets
gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
gtk_window_set_title (GTK_WINDOW (window), "GTK Entry");
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect_swapped (G_OBJECT (window), "delete_event",
G_CALLBACK (gtk_widget_destroy),
window);
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show (vbox);
entry = gtk_entry_new ();
gtk_entry_set_max_length (GTK_ENTRY (entry), 50);
g_signal_connect (G_OBJECT (entry), "activate",
G_CALLBACK (enter_callback),
entry);
gtk_entry_set_text (GTK_ENTRY (entry), "hello");
tmp_pos = GTK_ENTRY (entry)->text_length;
gtk_editable_insert_text (GTK_EDITABLE (entry), " world", -1, &tmp_pos);
gtk_editable_select_region (GTK_EDITABLE (entry),
0, GTK_ENTRY (entry)->text_length);
gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
gtk_widget_show (entry);
hbox = gtk_hbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
gtk_widget_show (hbox);
check = gtk_check_button_new_with_label ("Editable");
gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
g_signal_connect (G_OBJECT (check), "toggled",
G_CALLBACK (entry_toggle_editable), entry);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
gtk_widget_show (check);
check = gtk_check_button_new_with_label ("Visible");
gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
g_signal_connect (G_OBJECT (check), "toggled",
G_CALLBACK (entry_toggle_visibility), entry);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
gtk_widget_show (check);
button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
g_signal_connect_swapped (G_OBJECT (button), "clicked",
G_CALLBACK (gtk_widget_destroy),
window);
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_widget_show (window);
78

Page 87
Chapter 9. Miscellaneous Widgets
gtk_main();
return 0;
}
9.9. Spin Buttons
The Spin Button widget is generally used to allow the user to select a value from a range of numeric
values. It consists of a text entry box with up and down arrow buttons attached to the side. Selecting one
of the buttons causes the value to "spin" up and down the range of possible values. The entry box may
also be edited directly to enter a specific value.
The Spin Button allows the value to have zero or a number of decimal places and to be
incremented/decremented in configurable steps. The action of holding down one of the buttons
optionally results in an acceleration of change in the value according to how long it is depressed.
The Spin Button uses an Adjustment object to hold information about the range of values that the spin
button can take. This makes for a powerful Spin Button widget.
Recall that an adjustment widget is created with the following function, which illustrates the information
that it holds:
GtkObject *gtk_adjustment_new( gdouble value,
gdouble lower,
gdouble upper,
gdouble step_increment,
gdouble page_increment,
gdouble page_size );
These attributes of an Adjustment are used by the Spin Button in the following way:
value
: initial value for the Spin Button
lower
: lower range value
upper
: upper range value
step_increment
: value to increment/decrement when pressing mouse button 1 on a button
page_increment
: value to increment/decrement when pressing mouse button 2 on a button
page_size
: unused
Additionally, mouse button 3 can be used to jump directly to the
upper
or
lower
values when used to
select one of the buttons. Lets look at how to create a Spin Button:
GtkWidget *gtk_spin_button_new( GtkAdjustment *adjustment,
79

Page 88
Chapter 9. Miscellaneous Widgets
gdouble
climb_rate,
guint
digits );
The
climb_rate